摘要:由于的自動內(nèi)存管理系統(tǒng)要求對象起始地址必須是字節(jié)的整數(shù)倍,換句話說,就是對象的大小必須是字節(jié)的整數(shù)倍。對象大小計算要點(diǎn)在位系統(tǒng)下,存放指針的空間大小是字節(jié),是字節(jié),對象頭為字節(jié)。靜態(tài)屬性不算在對象大小內(nèi)。
jvm系列
垃圾回收基礎(chǔ)
JVM的編譯策略
GC的三大基礎(chǔ)算法
GC的三大高級算法
GC策略的評價指標(biāo)
JVM信息查看
GC通用日志解讀
jvm的card table數(shù)據(jù)結(jié)構(gòu)
Java類初始化順序
Java對象結(jié)構(gòu)及大小計算
Java的類加載機(jī)制
Java對象分配簡要流程
年老代過大有什么影響
Survivor空間溢出實(shí)例
關(guān)于Object=null
Java線程與Xss
序本文主要簡述Java對象的內(nèi)存布局以及其大小的計算。
Java對象內(nèi)存布局在HotSpot虛擬機(jī)中,對象在內(nèi)存中存儲的布局可以分為3塊區(qū)域:對象頭(Header)、實(shí)例數(shù)據(jù)(Instance Data)和對齊填充(Padding)。
對象頭HotSpot虛擬機(jī)的對象頭包括兩部分信息:
第一部分markword,用于存儲對象自身的運(yùn)行時數(shù)據(jù),如哈希碼(HashCode)、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有的鎖、偏向線程ID、偏向時間戳等,這部分?jǐn)?shù)據(jù)的長度在32位和64位的虛擬機(jī)(未開啟壓縮指針)中分別為32bit和64bit,官方稱它為“MarkWord”。
對象頭的另外一部分是klass,類型指針,即對象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過這個指針來確定這個對象是哪個類的實(shí)例.
實(shí)例數(shù)據(jù)實(shí)例數(shù)據(jù)部分是對象真正存儲的有效信息,也是在程序代碼中所定義的各種類型的字段內(nèi)容。無論是從父類繼承下來的,還是在子類中定義的,都需要記錄起來。
對齊填充第三部分對齊填充并不是必然存在的,也沒有特別的含義,它僅僅起著占位符的作用。由于HotSpot VM的自動內(nèi)存管理系統(tǒng)要求對象起始地址必須是8字節(jié)的整數(shù)倍,換句話說,就是對象的大小必須是8字節(jié)的整數(shù)倍。而對象頭部分正好是8字節(jié)的倍數(shù)(1倍或者2倍),因此,當(dāng)對象實(shí)例數(shù)據(jù)部分沒有對齊時,就需要通過對齊填充來補(bǔ)全。
對象大小計算 要點(diǎn)在32位系統(tǒng)下,存放Class指針的空間大小是4字節(jié),MarkWord是4字節(jié),對象頭為8字節(jié)。
在64位系統(tǒng)下,存放Class指針的空間大小是8字節(jié),MarkWord是8字節(jié),對象頭為16字節(jié)。
64位開啟指針壓縮的情況下,存放Class指針的空間大小是4字節(jié),MarkWord是8字節(jié),對象頭為12字節(jié)。
數(shù)組長度4字節(jié)+數(shù)組對象頭8字節(jié)(對象引用4字節(jié)(未開啟指針壓縮的64位為8字節(jié))+數(shù)組markword為4字節(jié)(64位未開啟指針壓縮的為8字節(jié)))+對齊4=16字節(jié)。
靜態(tài)屬性不算在對象大小內(nèi)。
實(shí)例import java.util.HashMap; /** * 64位開啟指針壓縮的話,markword變成8字節(jié),壓縮了class指針為4字節(jié),故對象頭12字節(jié) * 64位沒有開啟指針壓縮的話,markword8字節(jié),class指針8字節(jié),對象頭16字節(jié) * 32位markword為4字節(jié),class指針為4字節(jié),對象頭8字節(jié) * * 另外,靜態(tài)屬性所占用的空間通常不算在對象本身,因?yàn)樗囊檬窃诜椒▍^(qū)。 * * @author xixicat * @created 2014-10-03 */ public class ObjectSize { public static void main(String[] args){ System.out.println(SizeOfTool.getObjectSize(new A(),SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new B(),SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new C(),SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new D(),SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new E(),SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new Q(),SizeEnum.B)); /** * 64位壓縮指針下,對象頭12字節(jié),數(shù)組長度描述4字節(jié),數(shù)據(jù)4*100 =16+400 = 416 */ System.out.println(SizeOfTool.getObjectSize(new int[100],SizeEnum.B)); /** * 屬性4位對齊 * 64位壓縮指針下,對象頭12字節(jié),數(shù)組長度描述4字節(jié),數(shù)據(jù)1*100,對齊后104 = 16+104 = 120 */ System.out.println(SizeOfTool.getObjectSize(new byte[100],SizeEnum.B)); /** * 二維數(shù)組 * 64位指針壓縮下 * 第1維數(shù)組,對象頭12字節(jié),數(shù)組長度描述4字節(jié),2個數(shù)組引用共8字節(jié),共24字節(jié) * 第2維數(shù)組,對象頭12字節(jié),數(shù)組長度描述4字節(jié),100個數(shù)組引用共400字節(jié),對齊后共416字節(jié) * 第1維的2個引用所指對象大小 = 2*416 = 832 字節(jié) * 共24+832 = 856字節(jié) */ System.out.println(SizeOfTool.getObjectSize(new int[2][100],SizeEnum.B)); /** * 二維數(shù)組 * 64位指針壓縮下 * 第1維數(shù)組,對象頭12字節(jié),數(shù)組長度描述4字節(jié),100個數(shù)組引用共400字節(jié),共416字節(jié) * 第2維數(shù)組,對象頭12字節(jié),數(shù)組長度描述4字節(jié),2個數(shù)組引用共8字節(jié),共24字節(jié) * 第1維的100個引用所指對象大小 = 100*24 = 2400 字節(jié) * 共416+2400 = 2816字節(jié) */ System.out.println(SizeOfTool.getObjectSize(new int[100][2],SizeEnum.B)); System.out.println(SizeOfTool.getObjectSize(new Object(),SizeEnum.B)); /** * 不算static屬性 * private final char value[]; * private int hash; // Default to 0 * private transient int hash32 = 0; * * 32位下,String對象頭8字節(jié),2個int類型8字節(jié),char數(shù)組引用占4字節(jié),共占24字節(jié) * 另外,還要算上value[]數(shù)組的占用,數(shù)組對象頭部8字節(jié),數(shù)組長度4字節(jié),對齊后共占16字節(jié) * =》String對象對象大小24+16 = 40字節(jié) * 64位開啟指針壓縮下(壓縮指針),String對象頭12字節(jié),2個int類型8字節(jié),char數(shù)組引用占4字節(jié),共占24字節(jié) * 另外,還要算上value[]數(shù)組的占用,數(shù)組對象頭部12字節(jié),數(shù)組長度4字節(jié),對齊后共占16字節(jié) * =》String對象大小24+16=40字節(jié) */ System.out.println(SizeOfTool.getObjectSize(new String(),SizeEnum.B)); /** * transient Entry參考[] table = (Entry []) EMPTY_TABLE; * transient int size; * int threshold; * final float loadFactor; * transient int modCount; * * 64位開啟指針壓縮下,對象頭部12字節(jié),數(shù)組引用4字節(jié),3個int12字節(jié),float4字節(jié),共32字節(jié) * 另外,算上Entry [] = 對象頭12 +屬性16字節(jié)+數(shù)組長度4字節(jié) = 32字節(jié) * * final K key; * V value; * Entry next; * int hash; * * 對象頭12字節(jié),3個引用共12字節(jié),1個int4字節(jié) =》 一個entry至少占用28字節(jié) * * =》32+32=64字節(jié) */ System.out.println(SizeOfTool.getObjectSize(new HashMap(),SizeEnum.B)); } } //32位下對象頭8字節(jié),byte占1字節(jié),對其填充后,總占16字節(jié) //64位開啟指針壓縮下對象頭12字節(jié),byte1字節(jié),對齊后占16字節(jié) class A{ byte b1; } //32位下對象頭8字節(jié),8個byte8字節(jié),總16字節(jié) //64位開啟指針壓縮下對象頭12字節(jié),8個byte8字節(jié),對齊后占24字節(jié) class B{ byte b1,b2,b3,b4,b5,b6,b7,b8; } //32位下對象頭8字節(jié),9個byte9字節(jié),對其填充后,總24字節(jié) //64位開啟指針壓縮下對象頭12字節(jié),9個byte9字節(jié),對齊后占24字節(jié) class C{ byte b1,b2,b3,b4,b5,b6,b7,b8,b9; } //32位下對象頭8字節(jié),int占4字節(jié),引用占4字節(jié),共16字節(jié) //64位開啟指針壓縮下對象頭12字節(jié),int占4字節(jié),引用占4字節(jié),對齊后占24字節(jié) class D{ int i; String str; } //32位下對象頭8字節(jié),int4字節(jié),byte占1字節(jié),引用占4字節(jié),對其后,共24字節(jié) //64位開啟指針壓縮下對象頭12字節(jié),int占4字節(jié),引用占4字節(jié),byte占1字節(jié),對齊后占24字節(jié) class E{ int i; byte b; String str; } /** * 對齊有兩種 * 1、整個對象8字節(jié)對齊 * 2、屬性4字節(jié)對齊 **** * * 對象集成屬性的排布 * markword 4 8 * class指針 4 4 * 父類的父類屬性 1 1 * 屬性對齊 3 3 * 父類的屬性 1 1 * 屬性對齊 3 3 * 當(dāng)前類的屬性 1 1 * 屬性對齊填充 3 3 * 整個對象對齊 8+12 =》 24 12+12=》24 */ class O{ byte b; } class P extends O{ byte b; } class Q extends P{ byte b; }
深入理解Java虛擬機(jī)(第2版)
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/65601.html
摘要:對于不同的實(shí)現(xiàn),對象占用的內(nèi)存空間大小可能不盡相同,本文主要分析中的情況,實(shí)驗(yàn)環(huán)境為位系統(tǒng),使用進(jìn)行結(jié)論驗(yàn)證。內(nèi)存占用這里分析一個只有一組鍵值對的結(jié)構(gòu)如下首先分析本身的大小。 本文深入分析并驗(yàn)證了不同Java對象占用內(nèi)存空間大小的情況。對于不同的jvm實(shí)現(xiàn),Java對象占用的內(nèi)存空間大小可能不盡相同,本文主要分析HotSpot jvm中的情況,實(shí)驗(yàn)環(huán)境為64位window10系統(tǒng)、JD...
摘要:下面是線程相關(guān)的熱門面試題,你可以用它來好好準(zhǔn)備面試。線程安全問題都是由全局變量及靜態(tài)變量引起的。持有自旋鎖的線程在之前應(yīng)該釋放自旋鎖以便其它線程可以獲得自旋鎖。 最近看到網(wǎng)上流傳著,各種面試經(jīng)驗(yàn)及面試題,往往都是一大堆技術(shù)題目貼上去,而沒有答案。 不管你是新程序員還是老手,你一定在面試中遇到過有關(guān)線程的問題。Java語言一個重要的特點(diǎn)就是內(nèi)置了對并發(fā)的支持,讓Java大受企業(yè)和程序員...
摘要:本文詳細(xì)描述了堆內(nèi)存模型,垃圾回收算法以及處理內(nèi)存泄露的最佳方案,并輔之以圖表,希望能對理解內(nèi)存結(jié)構(gòu)有所幫助。該區(qū)域也稱為內(nèi)存模型的本地區(qū)。在中,內(nèi)存泄露是指對象已不再使用,但垃圾回收未能將他們視做不使用對象予以回收。 本文詳細(xì)描述了 Java 堆內(nèi)存模型,垃圾回收算法以及處理內(nèi)存泄露的最佳方案,并輔之以圖表,希望能對理解 Java 內(nèi)存結(jié)構(gòu)有所幫助。原文作者 Sumith Puri,...
摘要:在一般應(yīng)用中,不會逃逸的局部對象所占的比例很大,如果能使用棧上分配,那大量的對象就會隨著方法的結(jié)束而自動銷毀了,垃圾收集系統(tǒng)的壓力將會小很多。相關(guān)參數(shù)設(shè)置大對象直接進(jìn)入年老代的閾值,當(dāng)對象大小超過這個值時,將直接在年老代分配。 jvm系列 垃圾回收基礎(chǔ) JVM的編譯策略 GC的三大基礎(chǔ)算法 GC的三大高級算法 GC策略的評價指標(biāo) JVM信息查看 GC通用日志解讀 jvm的card t...
摘要:注意空類的大小,空類比較特殊,編譯器給了空類一個字節(jié)來唯一標(biāo)識這個類。如果一個類沒有對象,那么它的對象需要給進(jìn)行占位,標(biāo)識對象存在,這不存儲有效數(shù)據(jù)。 類 類的使...
閱讀 3940·2021-10-12 10:12
閱讀 2899·2021-09-10 11:18
閱讀 3684·2019-08-30 15:54
閱讀 2816·2019-08-30 15:53
閱讀 651·2019-08-30 13:54
閱讀 977·2019-08-30 13:21
閱讀 2270·2019-08-30 12:57
閱讀 1700·2019-08-30 11:10