天天看點

jvm兩種方式擷取對象所占用的記憶體通過Instrumentation來計算對象的大小使用Unsafe類來擷取對象大小下面我們進行一個簡單的驗證:

在開發過程中,我們有時需要來擷取某個對象的大小,以友善我們參考,來決定開發的技術方案。jvm中提供了兩種方式來擷取一個對象的大小。

編寫計算代碼:

其中sizeof方法僅僅擷取的是目前對象的大小,而該對象的如果存在對其他對象的引用,則不在計算範圍以内,而fullsizeof則會計算整體的大小。

将該java檔案進行編譯,并打成jar包

com.java.basic.SizeOfAgent .java

jar cvf sizeOfAgent.jar com/java.basic/SizeOfAgent .class

修改META-INF/MANIFEST.MF檔案内容

Premain-Class: com.java.basic.SizeOfAgent

Boot-Class-Path:

Can-Redefine-Classes: false

注意:每個冒号後面都有一個空格,且最後一行會有一個換行

将該jar包導入項目

添加啟動參數:-javaagent:E:\sizeOfAgent.jar

我這邊是将該jar包放在e盤,這裡填寫絕對路徑。

這樣我們就可以通過調用該類中的sizeOf方法或者fullSizeOf方法即可。

unsafe對象可以擷取到一個對象中各個屬性的記憶體指針的偏移量,可以利用其來計算一個對象的大小。

當我們需要計算一個對象大小時,我們隻需要擷取ClassIntrospector執行個體,并調用其introspect方法,參數為需要計算大小的對象,就可以擷取到ObjectInfo對象,這個對象中就包含了要計算的對象的各項資訊(名字,類型,屬性的偏移量等),想要擷取對象的大小,我們隻需要調用OjbectInfo的getDeepSiz即可。

ClassIntrospector中還定義了一個方法getObjectRefSize,這個方法的作用是擷取目前虛拟機對象引用指針所占的空間,如果機器的記憶體在32G以下,則會預設開啟指針壓縮,占4個位元組,否則占8個,可以使用參數-XX:-UseCompressedOops進行指針壓縮

首先我們先定義一個對象:

測試代碼:

運作結果:

兩種方法的運作結果一緻,我們進行對象的手動計算,計算公式:

mark頭(8位元組)+oop指針(4位元組)+對象屬性

以person對象為例:

mark頭(8位元組)+oop指針(4位元組)+name(String類型引用4位元組)+age(int類型引用4位元組)=20

jvm會對一個對象進行記憶體對齊,是的對象的大小為8的倍數,是以最終結果為24。

當然這兩種計算方式都是對對象的一個大概計算,當一個對象引用String類型時,其實是有常量池的存在的,是以計算出來的隻我們隻能做個參考即可。