前言
Java 程序調優是一個程序員必備的技能。
對象內存結構
對象頭:
Mark Word :32bit機 4B;64bit機 8B 是固定的。
類型指針:klass pointer,引用類型在方法區的地址。 開啟指針壓縮占4字節,不開啟占8個字節。
數組長度:對象不是數組占0字節,對象是數組占4字節,開啟指針壓縮,數組長度會放到類型指針的后半段。
對其填充:在關閉指令壓縮的情況下,數組類型還會進行填充,稱為兩段填充,還有很多中情況會出現填充。
實例數據:
類的非靜態屬性,基礎數據類型(byte 1字節,int 4字節,等等),引用類型:開啟指針壓縮4B,不開8字節。
對齊填充:
保證Java對象的大小都是8字節的整數倍,不足就不起, 例如對象前面的信息計算下來是31個字節,那就會補一個字節成32個字節。對齊填充的出現原因和內存分配有關,不需要獲取哦對象信息還要去多塊內存獲取組合。
計算對象大小
百度網盤: https://pan.baidu.com/s/1bk_qdV1jpo7qSBnLGJHgcw 提取碼: jafj 下載一個Jar包。
import org.openjdk.jol.info.ClassLayout; public class JvmTest4 { public static void main(String[] args) { Student student = new Student(); System.out.println(ClassLayout.parseInstance(student).toPrintable()); } }
運行結果:
-XX:+/-UseCompressedOops -- 開啟或者關閉指針壓縮。
案例
import org.openjdk.jol.info.ClassLayout; public class JvmTest4 { static int[] a = new int[]{1,2,3}; public static void main(String[] args) { System.out.println(ClassLayout.parseInstance(a).toPrintable()); } }
運行結果:
這個案例是關不指針壓縮下運行的, 可以很好的看到有兩階段提交的功能。
指針壓縮
因為Java對象是8字節對齊的,所有對象對應的字節最后3位一定是000,故存儲的時候可以去掉后面3個0。
面試題:Java堆內存最大允許多少,為什么?
對象頭中的類型指針指向的就是對象引用變量在方法區的地址,通過這個地址可以找到整個對象的全部內容在內存中位置。
類型指針在開啟指針壓縮的情況下,占用4個字節即32位,2的32次方就是4G,類型指針最大可以存在4G內存的位置。 又因為每個對象在開啟指針壓縮的情況下,最后3位000會被去掉。 所以實際4個字節可以表示 2的35次方-2的3次方的最大內存地址,即32G內存的最大位置。
因為現在都是64位機器了,那么如果電腦或者服務器的內存超過32G內存,在開啟指針壓縮的情況下就是出現找不到內存地址情況?
如果在開啟指針壓縮下優化這個問題,可以將Java對象的8字節對齊改成16字節對其,甚至32字節對其。這個能表示的內存最大值就是64G,128G了。 這個需要修改JDK源碼。
總結
Jvm的對象的結構,指針壓縮對我們后續遇到問題,能夠提供非常好的基礎鋪墊。