国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁技術文章
文章詳情頁

一個Java對象到底占多大內存?

瀏覽:70日期:2022-09-06 09:21:43

最近在讀《深入理解Java虛擬機》,對Java對象的內存布局有了進一步的認識,于是腦子里自然而然就有一個很普通的問題,就是一個Java對象到底占用多大內存?

在網上搜到了一篇博客講的非常好:http://yueyemaitian.iteye.com/blog/2033046,里面提供的這個類也非常實用:

import java.lang.instrument.Instrumentation; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayDeque; import java.util.Deque; import java.util.HashSet; import java.util.Set; /** * 對象占用字節大小工具類 * * @author tianmai.fh * @date 2014-03-18 11:29 */ public class SizeOfObject { static Instrumentation inst;public static void premain(String args, Instrumentation instP) { inst = instP; }/** * 直接計算當前對象占用空間大小,包括當前類及超類的基本類型實例字段大小、<br></br> * 引用類型實例字段引用大小、實例基本類型數組總占用空間、實例引用類型數組引用本身占用空間大小;<br></br> * 但是不包括超類繼承下來的和當前類聲明的實例引用字段的對象本身的大小、實例引用數組引用的對象本身的大小 <br></br> * * @param obj * @return */ public static long sizeOf(Object obj) { return inst.getObjectSize(obj); }/** * 遞歸計算當前對象占用空間總大小,包括當前類和超類的實例字段大小以及實例字段引用對象大小 * * @param objP * @return * @throws IllegalAccessException */ public static long fullSizeOf(Object objP) throws IllegalAccessException { Set<Object> visited = new HashSet<Object>(); Deque<Object> toBeQueue = new ArrayDeque<Object>(); toBeQueue.add(objP); long size = 0L; while (toBeQueue.size() > 0) { Object obj = toBeQueue.poll(); //sizeOf的時候已經計基本類型和引用的長度,包括數組 size += skipObject(visited, obj) ? 0L : sizeOf(obj); Class<?> tmpObjClass = obj.getClass(); if (tmpObjClass.isArray()) { //[I , [F 基本類型名字長度是2 if (tmpObjClass.getName().length() > 2) { for (int i = 0, len = Array.getLength(obj); i < len; i++) { Object tmp = Array.get(obj, i); if (tmp != null) { //非基本類型需要深度遍歷其對象 toBeQueue.add(Array.get(obj, i)); } } } } else { while (tmpObjClass != null) { Field[] fields = tmpObjClass.getDeclaredFields(); for (Field field : fields) { if (Modifier.isStatic(field.getModifiers()) //靜態不計 || field.getType().isPrimitive()) { //基本類型不重復計 continue; } field.setAccessible(true); Object fieldValue = field.get(obj); if (fieldValue == null) { continue; } toBeQueue.add(fieldValue); } tmpObjClass = tmpObjClass.getSuperclass(); } } } return size; }/** * String.intern的對象不計;計算過的不計,也避免死循環 * * @param visited * @param obj * @return */ static boolean skipObject(Set<Object> visited, Object obj) { if (obj instanceof String && obj == ((String) obj).intern()) { return true; } return visited.contains(obj); } }

大家可以用這個代碼邊看邊驗證,注意的是,運行這個程序需要通過javaagent注入Instrumentation,具體可以看原博客。我今天主要是總結下手動計算Java對象占用字節數的基本規則,做為基本的技能必須get√,希望能幫到和我一樣的Java菜鳥。

在介紹之前,簡單回顧下,Java對象的內存布局:對象頭(Header),實例數據(Instance Data)和對齊填充(Padding),詳細的可以看我的讀書筆記。另外:不同的環境結果可能有差異,我所在的環境是HotSpot虛擬機,64位Windwos。

下面進入正文:

對象頭

對象頭在32位系統上占用8bytes,64位系統上占用16bytes。

一個Java對象到底占多大內存?

一個Java對象到底占多大內存?

實例數據

原生類型(primitive type)的內存占用如下:

Primitive TypeMemory Required(bytes)boolean1byte1short2char2int4float4long8double8

reference類型在32位系統上每個占用4bytes, 在64位系統上每個占用8bytes。

對齊填充

HotSpot的對齊方式為8字節對齊:

(對象頭 + 實例數據 + padding) % 8等于0且0 <= padding < 8

指針壓縮

對象占用的內存大小收到VM參數UseCompressedOops的影響。

1)對對象頭的影響

開啟(-XX:+UseCompressedOops)對象頭大小為12bytes(64位機器)。

static class A {int a; }

A對象占用內存情況:

關閉指針壓縮: 16+4=20不是8的倍數,所以+padding/4=24

一個Java對象到底占多大內存?

開啟指針壓縮: 12+4=16已經是8的倍數了,不需要再padding。

一個Java對象到底占多大內存?

2) 對reference類型的影響

64位機器上reference類型占用8個字節,開啟指針壓縮后占用4個字節。

static class B2 {int b2a;Integer b2b;}

B2對象占用內存情況:

關閉指針壓縮: 16+4+8=28不是8的倍數,所以+padding/4=32

一個Java對象到底占多大內存?

開啟指針壓縮: 12+4+4=20不是8的倍數,所以+padding/4=24

一個Java對象到底占多大內存?

數組對象

64位機器上,數組對象的對象頭占用24個字節,啟用壓縮之后占用16個字節。之所以比普通對象占用內存多是因為需要額外的空間存儲數組的長度。

先考慮下new Integer[0]占用的內存大小,長度為0,即是對象頭的大小:

未開啟壓縮:24bytes

一個Java對象到底占多大內存?

開啟壓縮后:16bytes

一個Java對象到底占多大內存?

接著計算new Integer[1],new Integer[2],new Integer[3]和new Integer[4]就很容易了:

未開啟壓縮:

一個Java對象到底占多大內存?

開啟壓縮:

一個Java對象到底占多大內存?

拿new Integer[3]來具體解釋下:

未開啟壓縮:24(對象頭)+8*3=48,不需要padding;

開啟壓縮:16(對象頭)+3*4=28,+padding/4=32,其他依次類推。

自定義類的數組也是一樣的,比如:

static class B3 {int a;Integer b; }

new B3[3]占用的內存大小:

未開啟壓縮:48

開啟壓縮后:32

復合對象

計算復合對象占用內存的大小其實就是運用上面幾條規則,只是麻煩點。

1)對象本身的大小

直接計算當前對象占用空間大小,包括當前類及超類的基本類型實例字段大小、引用類型實例字段引用大小、實例基本類型數組總占用空間、實例引用類型數組引用本身占用空間大小; 但是不包括超類繼承下來的和當前類聲明的實例引用字段的對象本身的大小、實例引用數組引用的對象本身的大小。

static class B {int a;int b; }static class C {int ba;B[] as = new B[3];C() { for (int i = 0; i < as.length; i++) {as[i] = new B(); }} }

未開啟壓縮:16(對象頭)+4(ba)+8(as引用的大?。?padding/4=32

開啟壓縮:12+4+4+padding/4=24

2)當前對象占用的空間總大小

遞歸計算當前對象占用空間總大小,包括當前類和超類的實例字段大小以及實例字段引用對象大小。

遞歸計算復合對象占用的內存的時候需要注意的是:對齊填充是以每個對象為單位進行的,看下面這個圖就很容易明白。

一個Java對象到底占多大內存?

現在我們來手動計算下C對象占用的全部內存是多少,主要是三部分構成:C對象本身的大小+數組對象的大小+B對象的大小。

未開啟壓縮:

(16 + 4 + 8+4(padding)) + (24+ 8*3) +(16+8)*3 = 152bytes

開啟壓縮:

(12 + 4 + 4 +4(padding)) + (16 + 4*3 +4(數組對象padding)) + (12+8+4(B對象padding))*3= 128bytes

大家有興趣的可以試試。

實際工作中真正需要手動計算對象大小的場景應該很少,但是個人覺得做為基礎知識每個Java開發人員都應該了解,另外:對自己寫的代碼大概占用多少內存,內存中是怎么布局的應該有一個直覺性的認識。

標簽: Java
相關文章:
主站蜘蛛池模板: 亚洲在线网| 亚洲欧美精品一区天堂久久 | 日韩欧美第一页 | 久久国内精品自在自线软件 | 91成人免费视频 | 久久成人综合网 | 国产中文久久精品 | 99视频在线精品免费 | 欧美精品自拍 | 国产丝袜美腿高跟白浆 | 国产成人午夜极速观看 | 久青草免费视频手机在线观看 | 国产精品综合一区二区三区 | 亚洲午夜精品一级在线播放放 | 日韩中文字幕在线看 | 免费精品一区二区三区在线观看 | 韩国巨胸女三级视频网 | 男人的天堂在线 | 婷婷91| 美女黄18| 69性欧美| 久久久香蕉视频 | 亚洲美女在线播放 | 久久99久久成人免费播放 | 亚洲人成在线影院 | 手机看片在线播放 | 久久亚洲天堂 | 久久亚洲精品一区成人 | 国产免费高清在线精品一区 | 国产91一区二区在线播放不卡 | 露脸国产野战最新在线视频 | 直接在线观看的三级网址 | 久久精品国产一区二区三区 | 一级网站在线观看 | 国产91无套剧情在线播放 | 日本高清色本在线www | 永久精品免费影院在线观看网站 | 高清国产美女一级a毛片 | 亚洲国产99在线精品一区二区 | 狠狠色狠狠色综合日日32 | 久久视频精品53在线观看 |