色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

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

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

瀏覽:68日期: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,即是對象頭的大?。?/p>

未開啟壓縮: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]占用的內存大?。?/p>

未開啟壓縮: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
相關文章:
主站蜘蛛池模板: 欧美一级毛片怡红院 | 亚洲欧美另类在线视频 | 欧美另类视频在线观看 | 亚洲欧美另类日本久久影院 | 亚洲国产欧美一区二区欧美 | 美女舒服好紧太爽了视频 | 国产一级一级一级成人毛片 | 大学生久久香蕉国产线观看 | 欧美.亚洲.日本一区二区三区 | 日韩a一级欧美一级在线播放 | 日本特级淫片免费看 | 国产欧美日韩一区二区三区在线 | 免费特黄级夫费生活片 | 国产精品三区四区 | 成人亲子乱子伦视频 | 欧美成人tv在线观看免费 | 久久精品国产亚洲网站 | 嫩草影院在线观看网站成人 | 成人免费看毛片 | 成人高清视频在线观看 | 日本三级一区 | 91精品国产综合久久欧美 | 一区二区三区不卡在线 | 国产成人精品福利网站在线观看 | 亚洲高清无在码在线无弹窗 | 99在线观看 | 一级a级国产不卡毛片 | 毛片免费观看网址 | 香港三级日本三级人妇三级四 | 久久毛片久久毛 | 成人国产精品一级毛片视频 | 羞羞一区二区三区四区片 | 亚洲国产精品综合欧美 | 欧美日韩亚洲国产精品 | 一个人的视频日本免费 | 亚洲精品国产专区91在线 | 免费一级α片在线观看 | 在线播放亚洲视频 | 在线视频中文 | 午夜精品一区二区三区在线观看 | 欧美怡红院高清在线 |