JVM之指針壓縮&內存如何設置


  在32位到64位的轉變中,人們最大的獲益是內存容量。在一個32位的系統中,內存地址的寬度就是32位,這就意味着,我們最大能獲取的內存空間是2^32(也就是4G)字節。這個容量明顯不夠用!在一個64位的機器中,理論上,我們能獲取到的內存容量是2^64字節,這是一個十分龐大的數字。可惜的是,這只是一個理論值,而現實中,因為有一堆有關硬件和軟件的因素限制,我們能得到的內存要少得多。舉個例了來說,最好的 linux 系統最多支持到16TB的內存,而且截止到現在 java11 也在正在研制最新一代的垃圾收集器 ZGC ,號稱可以支持到 TB 幾倍的且能保證 STW 時間不會太長,可能許多人會說“16TB好大呀”,但是和2^64比起來,它真的挺小的。好了,接下來,我們就談談compressed oops能幫我們做什么。

什么是 OOP ?

  在堆中,32位的對象引用(指針)占4個字節,而64位的對象引用占8個字節。64位JVM在支持更大堆的同時,由於對象引用變大卻帶來了性能問題:

  1. 增加了GC開銷:64位對象引用需要占用更多的堆空間,留給其他數據的空間將會減少,從而加快了GC的發生,更頻繁的進行GC。
  2. 降低CPU緩存命中率:64位對象引用增大了,CPU能緩存的oop將會更少,從而降低了CPU緩存的效率。

  為了能夠保持32位的性能,oop必須保留32位。那么,如何用32位oop來引用更大的堆內存呢?答案是——壓縮指針(CompressedOops)。

  OOP = “ordinary object pointer” 普通對象指針。 啟用CompressOops后,會壓縮的對象:

    1. 每個Class的屬性指針(靜態成員變量)

    2. 每個對象的屬性指針

    3. 普通對象數組的每個元素指針

  當然,壓縮也不是萬能的,針對一些特殊類型的指針,JVM是不會優化的。 比如指向 PermGen的Class 對象指針,本地變量,堆棧元素,入參,返回值,NULL指針不會被壓縮

1)CompressedOops原理:

  JVM的實現方式是,不再保存所有引用,而是每隔8個字節保存一個引用。例如,原來保存每個引用0、1、2...,現在只保存0、8、16...。因此,指針壓縮后,並不是所有引用都保存在堆中,而是以8個字節為間隔保存引用。

  CompressedOops,可以讓跑在64位平台下的JVM,不需要因為更寬的尋址,而付出Heap容量損失的代價。 不過它的實現方式是在機器碼中植入壓縮與解壓指令,可能會給JVM增加額外的開銷。

2)零基壓縮優化(Zero Based Compressd Oops)

  零基壓縮是針對 壓、解壓 動作的進一步優化。 它通過改變正常指針的隨機地址分配特性,強制堆地址從零開始分配(需要OS支持),進一步提高了壓解壓效率。要啟用零基壓縮,你分配給JVM的內存大小必須控制在4G以上,32G以下。

3)總結:

  • 如果GC堆大小在 4G以下,直接砍掉高32位,避免了編碼解碼過程;
  • 如果GC堆大小在 4G以上32G以下,則啟用 UseCompressedOop;
  • 如果GC堆大小 大於32G,壓指失效,使用原來的64位(所以說服務器內存太大不好......)。

靈魂提問

  從以上結果中我們知道 32GB 以下是啟用了 UseCompressedOop,但是當我們線上真正啟動服務的時候直接設置 -Xmx=32GB 的時候很可能導致 CompressedOop 失效,那我們怎么確定當前環境下最大內存設置多大才且最大限度的使用內存才能啟動 CompressedOop 呢?

  32G是個近似值,這個臨界值跟JVM和平台有關。如果不想精確設置的話,31G是個絕對安全的數值,31G肯定默認開啟compressed oops。我們可以通過增加JVM參數 -XX:+PrintFlagsFinal,驗證UseCompressedOops的值,從而得知,到底是不是真的開啟了壓縮指針,還是壓縮指針失效!
  那我們就手動來驗證這個臨界值:

  32G,即32*1024=32768M,剛好在范圍[32760, 32770]中。而 32768m 驗證后得到並沒有開啟壓縮指針,所以可以從 32760 ~ 32768 之間驗證選擇一個最大的且開啟壓縮指針的內存大小。

簡單測試驗證

  我們來做了一個簡單測試,驗證一下這個問題:分配設置內存大小分別為:-Xmx32760m 和 -Xmx32770m,-Xmn 都是 100M(S0:S1:Eden默認1:1:8)。總計分配一個包含8個對象類型和8個原子類型以及String,總計17個類型屬性的對象 1kw 次。看它們分別觸發了多少 YGC,結論如下表所示:
實驗次數    開啟壓縮指針YGC次數    關閉壓縮指針YGC次數

 

   由執行結果可知,Young區完全一樣的情況下,開啟壓縮指針相比關閉壓縮指針,能節省20%多的內存。由此可知,32G還真是一個奇妙的魔法數值!另外需要說明的是YGC次數有小數,是表示Eden區占用比例,比如 17.52 次 YGC 表示發生了 17次 YGC 並且 Eden 還占了52%

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM