在做JVM內(nèi)存調(diào)優(yōu)的時候,我們免不了需要去計算對象的大小体捏。計算對象大小又要考慮是普通對象還是數(shù)組對象冠摄,因為普通對象與數(shù)組對象的對象頭存在些許差異。而且自JDK6以后几缭,為了節(jié)省內(nèi)存河泳、提高運行效率,又引入了新的技術(shù):指針壓縮
年栓。更加劇了計算對象大小的難度拆挥。
這篇文章就來深入分析如何計算對象大小,確保計算的結(jié)果與實際情況不差一個字節(jié)某抓。
對象結(jié)構(gòu)
對象結(jié)構(gòu)想必深入學(xué)習(xí)過JVM的人都知道竿刁,它分為三大部分:對象頭、實例數(shù)據(jù)搪缨、對齊填充。其中對象頭又分為三個部分:Mark Word鸵熟、類型指針副编、數(shù)組長度。其實對象頭還有第四部分流强,這是目前你看到的書痹届、視頻都沒有提到的呻待,對象頭也有對齊填充部分,這個部分也不是一定會有队腐,只有數(shù)組對象在未開啟指針壓縮的情況下才會出現(xiàn)蚕捉。是不是一臉懵,那就繼續(xù)往后看柴淘。
指針壓縮
看到這四個字是不是一堆的問號:這是什么迫淹?這怎么實現(xiàn)的?為什么說它節(jié)省了內(nèi)存为严?……咱們就來搞清楚這些個問題敛熬。
咱們先達(dá)成觀念上的一致:所有的對象都是以8字節(jié)對齊的。現(xiàn)在我有3個對象:test1(16字節(jié))第股、test2(32字節(jié))应民、test3(24字節(jié)),為了便于說明夕吻,假如這三個對象中間沒有其他對象诲锹,那他們的內(nèi)存地址是:
test1 = 0x0000 0 000(0字節(jié) ~ 16字節(jié))
test2 = 0x0001 0 000(16字節(jié) ~ 48字節(jié))
test3 = 0x0011 0 000(48字節(jié) ~ 72字節(jié))
大家發(fā)現(xiàn)規(guī)律了嗎,所有對象指針的后三位都是0涉馅,這就是指針壓縮的實現(xiàn)原理归园。開啟指針壓縮后,JVM會將對象指針的后三位給截去控漠,如果test2 = 0x10000蔓倍,在開啟指針后就變成了test2=0x10,在使用的時候?qū)⒑笕坏?補回去盐捷,即test2=0x10 000偶翅。
因為開啟了指針壓縮后,對象指針就變成了4字節(jié)(32位)碉渡,加上補3位聚谁,共35位。即開啟指針壓縮后一個對象指針能表示的最大堆空間是2的35次方滞诺,即32G形导。
那讀者可以想一想?如果我想擴充一個oop能表示的堆空間大小該怎么做呢习霹?
下面咱們來看四種情況(普通對象-關(guān)閉指針壓縮朵耕、普通對象-開啟指針壓縮、數(shù)組對象-關(guān)閉指針壓縮淋叶、數(shù)組對象-開啟指針壓縮)下的對象大小是如何計算出來的阎曹。建議讀者寫相似代碼測試一下,這樣才能理解得更深刻。\
測試代碼:
package com.qimingnan.adjust;
import org.openjdk.jol.info.ClassLayout;
public class Test1 {
int a = 10;
int b = 20;
static int[] arr = {0, 1, 2};
public static void main(String[] args) {
Test1 test1 = new Test1();
System.out.printf(ClassLayout.parseInstance(test1).toPrintable());
System.out.printf(ClassLayout.parseInstance(arr).toPrintable());
}
}
普通對象
一处嫌、未開啟指針壓縮
24B = 8B(Mark Word)+ 8B(KClass Pointer)+ 4B + 4B
二栅贴、開啟指針壓縮
24B = 8B(Mark Word)+ 4B(KClass Pointer)+ 4B(int a)+ 4B(int b)+ 4B(Padding)
數(shù)組對象
一、未開啟指針壓縮
40B = 8B(Mark Word)+ 8B(KClass Pointer)+ 4B(數(shù)組長度)+ 4B(頭部Padding)+ 12B(3個int)+ 4B(對象Padding)
二熏迹、開啟指針壓縮
32B = 8B(Mark Word)+ 4B(KClass Pointer)+ 4B(數(shù)組長度)+ 12B(3個int)+ 4B(對象Padding)
如何計算對象大小大家學(xué)會了嗎檐薯?
介紹一款工具,jol注暗,大家在做測試的時候可以借助這個工具
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
這篇文章有些地方可能不太好理解坛缕,讀者有問題的話,留言提問吧友存。我都會一一回復(fù)祷膳。
后續(xù)我將為大家新開《手寫JVM》的系列專欄,如果你對此感興趣的話屡立,那么就關(guān)注我吧直晨。