最近在看點不知道什么鬼的東西,看得到了一個讓我眼前一亮的新東西,感覺很有趣,記錄一下;
我們怎么知道一個java對象的大小呢?比如HashMap<String,Object> map = new HashMap<>();,這個map對象在堆中多大呢?占多少個字節呢?
我們可以借助apache的一個類RamUsageEstimator來計算,例如下面這種:
<dependency> <groupId>org.apache.lucene</groupId> <artifactId>lucene-core</artifactId> <version>6.6.1</version> </dependency>
Integer integer = new Integer(10); HashMap<String,Object> map = new HashMap<>();
System.out.println(RamUsageEstimator.shallowSizeOf(integer));//16 System.out.println(RamUsageEstimator.shallowSizeOf(map)); //48
我們可以看到最后計算出來的一個Integer是16個字節,一個HashMap是48個字節;
這個時候肯定會有人說,(#`㉨´)凸不對呀,不是說int類型是4個字節的嗎?為什么包裝類型Integer的就是16個字節了呢?
要知道這個問題,首先我們要知道在java堆中實例化的對象是由什么構成的?前面博客說了的,這里簡單的提一下,分三部分:對象頭,實例數據,對齊填充

主要說一下對象頭,對象頭由兩部分組成,64位jvm中markword占8個字節(一般都是64位的吧,32位的虛擬機就占4個字節),第二部分是klass類型的指針占4個字節!如果是數組,那么此處還有第三部分,數組長度占4個字節;
然后上面例子中Integer的對象頭應該是8+4=12,然后實例數據我們需要看Integer類以及父類中有幾個實例變量,只有一個,下圖所示(注意,是實例變量,不能是native和static修飾的),如果是引用類型就占4個字節用於記錄地址;int類型4個字節,於是12+4=16,剛好是8的倍數,無需對齊填充;

我們再說說那么HashMap,對象頭也是12,實例數據,我們要看看HashMap的父類有兩個屬性,是引用類型,每一個占4個字節;

再看看HashMap本類中有幾個屬性,可以看到6個,共占24個字節
transient Node<K,V>[] table;//引用類型,占四個字節 transient Set<Map.Entry<K,V>> entrySet;//引用類型,占四個字節 transient int size;//int類型,4個字節 transient int modCount;//int類型,4個字節 int threshold;//int類型,4個字節 final float loadFactor;//int類型,4個字節
所以就是12+4+4+24=44,由於java對象占的字節數必須要是8的倍數,所以對齊填充,在最后補4個字節,所以總共就是48個字節,很容易吧!
另外,想深入了解一下的java對象的組成,可以參考這篇博客,說的還是很詳細的:https://blog.csdn.net/haihui_yang/article/details/81071693
