參考博文: http://www.javamex.com/tutorials/memory/object_memory_usage.shtml
本文主要考慮正常情況下一個對象在堆上的內存占用情況:對於下面的特殊情況不作討論
1、某些情況下,JVM可能不會把對象存儲在堆上:比如小的線程私有對象原則上會全部存儲在棧或寄存器上,嚴格意義上說並不存在於java堆上
2、對象的內存占用可能依賴於它當前的狀態,比如說它的同步鎖是否處於競爭狀態、是否正處於垃圾回收階段(這些額外的“系統”數據不一定存儲在java堆上)
在HotSpot虛擬機上,一個java對象的內存占用一般包括如下幾部分:
1、一個對象頭部信息(包括幾字節的基本元信息)
2、原始類型字段的內存占用
3、引用字段的內存占用
4、對齊字節(padding):為了讓每個對象的開始地址是字節的整數倍,減少對象指針占用的比特數,對象數據后面會添加一些“無用”的數據(字節),以實現對齊,即保證最終的字節大小是8的倍數
HotSpot虛擬機的對象頭包含兩部分信息:1、用於存儲對象自身的運行時數據,這部分數據在32位和64位的虛擬機(未開啟壓縮指針)中分別為32bit和64bit。
2、類型指針,即對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例。注:如果java對象是一個數組,還必須包含用於記錄數組長度的數據,因為java虛擬機可以從普通java對象的元數據信息確定對象的大小,但是從數組的元數據中卻無法確定數組的大小。
下圖描述了32bit下對象頭的存儲狀態:
實例數據部分是對象真正存儲的有效信息:也即程序代碼定義的各種類型的字段內容。
這部分的存儲順序會受到虛擬機的的分配策略參數和字段在java源碼中定義的順序的影響。
java元數據類型占用字節列表:
可能會認為boolean會占用一比特或者占用一個字節的第八位,但是HotSpot虛擬機會為每個Boolean字段分配一個字節的空間。
在HotSpot中,每個對象占用的內存大小是 8 字節的倍數。如果對象所需的內存大小(包括頭信息和字段)不是 8 的倍數,則會向上取整到 8 的倍數。
也就是說:
1、一個空對象占用8字節
2、只有一個 boolean 字段的類實例占 16 字節:頭信息占 8 字節,boolean 占 1 字節,為了對齊達到 8 的倍數會額外占用 7 個字節
3、包含 8 個 boolean 字段的實例也會占用 16 字節:頭信息占用 8 字節,boolean 占用 8 字節;因為已經是 8 的倍數,不需要補充額外的數據來對齊
4、一個包含 2 個 long 字段、3 個 int 字段、1 個 boolean 字段的對象將占用:
- 頭信息占 8 字節;
- 2 個 long 字段占 16 字節(每個 long 字段占用 8 字節);
- 3 個 int 字段占 12 字節(每個 int 字段占用 4 字節);
- 1 個 boolean 字段占 1 個字節;
- 為了對齊額外多 3 個字節(上面加起來是 37 字節,為滿足對齊 8 的倍數 40)
關於二維數組占用字節數計算:注意數組有一個不同的地方在於,它本身會有一個記錄數組長度的int類型,占用4字節,本身又是一個對象,會占用8字節
For example, let's consider a 10x10 int array. Firstly, the "outer" array has its 12-byte object header followed by space for the 10 elements. Those elements are object references to the 10 arrays making up the rows. That comes to 12+4*10=52 bytes, which must then be rounded up to the next multiple of 8, giving 56. Then, each of the 10 rows has its own 12-byte object header, 4*10=40 bytes for the actual row of ints, and again, 4 bytes of padding to bring the total for that row to a multiple of 8. So in total, that gives 11*56=616 bytes. That's a bit bigger than if you'd just counted on 10*10*4=400 bytes for the hundred "raw" ints themselves.
關於java內存占用更為詳細的描述可以參考廖祜秋大神的博客:http://www.liaohuqiu.net/cn/posts/caculate-object-size-in-java/
廖神的博文中已經指出對於HotSpot,在32位的JVM中,一個對象引用占用4字節,而在64位的JVM中,一個對象引用占用8字節(在開啟指針壓縮的話占用4字節),而在Dalvik中則是始終占用4字節。
針對Dalvik,元數據類型的大小分別在作為對象域或變量,以及數組的一個元素時是不同的
在Dalvik中對象對齊邊界也是8字節,但是一個對象的內存占用和HotSpot是不同的:
會有一個額外的dlmalloc空間占用,4或8字節
所以一個空對象會占用16字節(12字節的內存占用以及4字節的對齊)
示例演示:
class EmptyClass { }
Total size: 8 (Object overhead) + 4 (dlmalloc) = 12 bytes. For 8 bytes alignment, the final total size is 16 bytes.
class Integer { int value; // 4 bytes }
The total size is: 8 + 4 + 4 (int) = 16 bytes.
static class HashMapEntry<K, V> { final K key; // 4 bytes final int hash; // 4 bytes V value; // 4 bytes HashMapEntry<K, V> next; // 4 bytes }
The total size: 8 + 4 + 4 * 4 = 28 bytes. Total aligned is 32 bytes.
詳細描述參考廖神博文:http://www.liaohuqiu.net/posts/android-object-size-dalvik/