關於字節對齊以及內存佔用

參考博文: http://www.javamex.com/tutorials/memory/object_memory_usage.shtmlhtml

本文主要考慮正常狀況下一個對象在堆上的內存佔用狀況:對於下面的特殊狀況不做討論java

一、某些狀況下,JVM可能不會把對象存儲在堆上:好比小的線程私有對象原則上會所有存儲在棧或寄存器上,嚴格意義上說並不存在於java堆上android

二、對象的內存佔用可能依賴於它當前的狀態,好比說它的同步鎖是否處於競爭狀態、是否正處於垃圾回收階段(這些額外的「系統」數據不必定存儲在java堆上)數組

在HotSpot虛擬機上,一個java對象的內存佔用通常包括以下幾部分:ide

一、一個對象頭部信息(包括幾字節的基本元信息)post

二、原始類型字段的內存佔用spa

三、引用字段的內存佔用.net

四、對齊字節(padding):爲了讓每一個對象的開始地址是字節的整數倍,減小對象指針佔用的比特數,對象數據後面會添加一些「無用」的數據(字節),以實現對齊,即保證最終的字節大小是8的倍數線程

HotSpot虛擬機的對象頭包含兩部分信息:一、用於存儲對象自身的運行時數據,這部分數據在32位和64位的虛擬機(未開啓壓縮指針)中分別爲32bit和64bit。3d

二、類型指針,即對象指向它的類元數據的指針,虛擬機經過這個指針來肯定這個對象是哪一個類的實例。注:若是java對象是一個數組,還必須包含用於記錄數組長度的數據,由於java虛擬機能夠從普通java對象的元數據信息肯定對象的大小,可是從數組的元數據中卻沒法肯定數組的大小。

下圖描述了32bit下對象頭的存儲狀態:

實例數據部分是對象真正存儲的有效信息:也即程序代碼定義的各類類型的字段內容。

這部分的存儲順序會受到虛擬機的的分配策略參數和字段在java源碼中定義的順序的影響。

java元數據類型佔用字節列表:

可能會認爲boolean會佔用一比特或者佔用一個字節的第八位,可是HotSpot虛擬機會爲每一個Boolean字段分配一個字節的空間。

在HotSpot中,每一個對象佔用的內存大小是 8 字節的倍數。若是對象所需的內存大小(包括頭信息和字段)不是 8 的倍數,則會向上取整到 8 的倍數。

也就是說:

一、一個空對象佔用8字節

二、只有一個 boolean 字段的類實例佔 16 字節:頭信息佔 8 字節,boolean 佔 1 字節,爲了對齊達到 8 的倍數會額外佔用 7 個字節

三、包含 8 個 boolean 字段的實例也會佔用 16 字節:頭信息佔用 8 字節,boolean 佔用 8 字節;由於已是 8 的倍數,不須要補充額外的數據來對齊

四、一個包含 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/

相關文章
相關標籤/搜索