一个Java对象到底占用多大内存?
最近在調(diào)研MAT和VisualVM源碼實現(xiàn),遇到一個可疑問題,兩者計算出來的對象大小不一致,才有了這樣疑惑。
一個Java對象到底占用多大內(nèi)存?
為了復現(xiàn)這個問題,準備了4個最簡單類:
class AAAAA {}class BBBBB {int a = 1;}class CCCCC {long a = 1L;}class DDDDD {String s = "hello";}當然了,再來個主函數(shù):
final List<AAAAA> aaa = new ArrayList<>(100000); final List<BBBBB> bbb = new ArrayList<>(100000); final List<CCCCC> ccc = new ArrayList<>(100000); final List<DDDDD> ddd = new ArrayList<>(100000);for (int i = 0; i < 100000; i++) {aaa.add(new AAAAA());bbb.add(new BBBBB());ccc.add(new CCCCC());ddd.add(new DDDDD());}本地的執(zhí)行環(huán)境是64位的JDK8,且使用默認的啟動參數(shù),運行之后通過 jmap-dump命令生成dump文件,分別用MAT和VisualVM打開。
MAT
通過MAT打開,可以發(fā)現(xiàn)ABD對象大小都是16字節(jié),而C對象大小為24字節(jié)
VisualVM
通過Vis打開,可以發(fā)現(xiàn)其顯示的大小和MAT有蠻大的差別。
好奇怪,哪個是對的?
要回答這個問題,首先得清楚的知道JVM中對象的內(nèi)存布局。
在Hotspot中,一個對象包含3個部分:對象頭、實例數(shù)據(jù)和對齊填充。
對象頭
這里不講對象頭是個什么東西,感興趣的同學可以看我的其它文章。 對象頭的大小一般和系統(tǒng)的位數(shù)有關(guān),也和啟動參數(shù) UseCompressedOops有關(guān):
-
32位系統(tǒng),占用 8 字節(jié)
-
64位系統(tǒng),開啟?UseCompressedOops時,占用 12 字節(jié),否則是16字節(jié)
實例數(shù)據(jù)
原生類型的內(nèi)存占用情況如下:
-
boolean 1
-
byte 1
-
short 2
-
char 2
-
int 4
-
float 4
-
long 8
-
double 8
引用類型的內(nèi)存占用和系統(tǒng)位數(shù)以及啟動參數(shù) UseCompressedOops有關(guān)
-
32位系統(tǒng)占4字節(jié)
-
64位系統(tǒng),開啟?UseCompressedOops時,占用4字節(jié),否則是8字節(jié)
對齊填充
在Hotspot中,為了更加容易的管理內(nèi)存,一般會使用8字節(jié)進行對齊。
意思是每次分配的內(nèi)存大小一定是8的倍數(shù),如果對象頭+實例數(shù)據(jù)的值不是8的倍數(shù),那么會重新計算一個較大值,進行分配。
結(jié)果
有了對象各部分的內(nèi)存占用大小,可以很輕松的計算出ABCD各對象在64位系統(tǒng),且開啟 UseCompressedOops參數(shù)時的大小。
-
A對象只包含一個對象頭,大小占12字節(jié),不是8的倍數(shù),需要4字節(jié)進行填充,一共占16字節(jié)
-
B對象包含一個對象頭和int類型,12+4=16,正好是8的倍數(shù),不需要填充。
-
C對象包含一個對象頭和long類型,12+8=20,不是8的倍數(shù),需要4個字節(jié)進行填充,占24字節(jié)
-
D對象包含一個對象頭和引用類型,12+4=16,正好是8的倍數(shù),不需要填充。
可以得出,VisualVM的顯示結(jié)果有點問題,主要因為以下兩點:
-
首先,沒有考慮是否開啟?UseCompressedOops
-
其次,沒有考慮內(nèi)存對齊填充的情況
感興趣的同學,可以動手實踐一下,這樣可以加深對象內(nèi)存布局的理解。
經(jīng)過這段時間對MAT和VisualVM的源碼研究,發(fā)現(xiàn)MAT的功能不是強大一點點,建議大家以后盡量使用MAT。
總結(jié)
以上是生活随笔為你收集整理的一个Java对象到底占用多大内存?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 震惊!原来这才是Kafka的“真面目”!
- 下一篇: 一文理解微服务架构下的系统可用性如何保证