Java 8的元空間

本文我們將會介紹JVM的一個更新,這就是持久代的移除。我們會介紹爲什麼需要移除持久代,以及它的替代者,元空間(metaspace)。這是上一篇文章內存管理之垃圾回收的續集。

Java 6中的堆結構是這樣的:

持久代

持久代中包含了虛擬機中所有可通過反射獲取到的數據,比如Class和Method對象。不同的Java虛擬機之間可能會進行類共享,因此持久代又分爲只讀區和讀寫區。

JVM用於描述應用程序中用到的類和方法的元數據也存儲在持久代中。JVM運行時會用到多少持久代的空間取決於應用程序用到了多少類。除此之外,Java SE庫中的類和方法也都存儲在這裏。

如果JVM發現有的類已經不再需要了,它會去回收(卸載)這些類,將它們的空間釋放出來給其它類使用。Full GC會進行持久代的回收。

  • JVM中類的元數據在Java堆中的存儲區域。
  • Java類對應的HotSpot虛擬機中的內部表示也存儲在這裏。
  • 類的層級信息,字段,名字。
  • 方法的編譯信息及字節碼。
  • 變量
  • 常量池和符號解析

持久代的大小

  • 它的上限是MaxPermSize,默認是64M
  • Java堆中的連續區域 : 如果存儲在非連續的堆空間中的話,要定位出持久代到新對象的引用非常複雜並且耗時。卡表(card table),是一種記憶集(Remembered Set),它用來記錄某個內存代中普通對象指針(oops)的修改。
  • 持久代用完後,會拋出OutOfMemoryError "PermGen space"異常。解決方案:應用程序清理引用來觸發類卸載;增加MaxPermSize的大小。
  • 需要多大的持久代空間取決於類的數量,方法的大小,以及常量池的大小。

爲什麼移除持久代

  • 它的大小是在啓動時固定好的——很難進行調優。-XX:MaxPermSize,設置成多少好呢?
  • HotSpot的內部類型也是Java對象:它可能會在Full GC中被移動,同時它對應用不透明,且是非強類型的,難以跟蹤調試,還需要存儲元數據的元數據信息(meta-metadata)。
  • 簡化Full GC:每一個回收器有專門的元數據迭代器。
  • 可以在GC不進行暫停的情況下併發地釋放類數據。
  • 使得原來受限於持久代的一些改進未來有可能實現

那麼JVM的元數據都去哪兒了?

元空間(metaspace)

持久代的空間被徹底地刪除了,它被一個叫元空間的區域所替代了。持久代刪除了之後,很明顯,JVM會忽略PermSize和MaxPermSize這兩個參數,還有就是你再也看不到java.lang.OutOfMemoryError: PermGen error的異常了。

JDK 8的HotSpot JVM現在使用的是本地內存來表示類的元數據,這個區域就叫做元空間。

元空間的特點:

  • 充分利用了Java語言規範中的好處:類及相關的元數據的生命週期與類加載器的一致。
  • 每個加載器有專門的存儲空間
  • 只進行線性分配
  • 不會單獨回收某個類
  • 省掉了GC掃描及壓縮的時間
  • 元空間裏的對象的位置是固定的
  • 如果GC發現某個類加載器不再存活了,會把相關的空間整個回收掉

元空間的內存分配模型

  • 絕大多數的類元數據的空間都從本地內存中分配
  • 用來描述類元數據的類也被刪除了
  • 分元數據分配了多個虛擬內存空間
  • 給每個類加載器分配一個內存塊的列表。塊的大小取決於類加載器的類型; sun/反射/代理對應的類加載器的塊會小一些
  • 歸還內存塊,釋放內存塊列表
  • 一旦元空間的數據被清空了,虛擬內存的空間會被回收掉
  • 減少碎片的策略

我們來看下JVM是如何給元數據分配虛擬內存的空間的

你可以看到虛擬內存空間是如何分配的(vs1,vs2,vs3) ,以及類加載器的內存塊是如何分配的。CL是Class Loader的縮寫。

理解_mark和_klass指針

要想理解下面這張圖,你得搞清楚這些指針都是什麼東西。

JVM中,每個對象都有一個指向它自身類的指針,不過這個指針只是指向具體的實現類,而不是接口或者抽象類。

對於32位的JVM:

_mark : 4字節常量

_klass: 指向類的4字節指針 對象的內存佈局中的第二個字段( _klass,在32位JVM中,相對對象在內存中的位置的偏移量是4,64位的是8)指向的是內存中對象的類定義。

64位的JVM:

_mark : 8字節常量

_klass: 指向類的8字節的指針

開啓了指針壓縮的64位JVM: _mark : 8字節常量

_klass: 指向類的4字節的指針

Java對象的內存佈局

類指針壓縮空間(Compressed Class Pointer Space)

只有是64位平臺上啓用了類指針壓縮纔會存在這個區域。對於64位平臺,爲了壓縮JVM對象中的_klass指針的大小,引入了類指針壓縮空間(Compressed Class Pointer Space)。

壓縮指針後的內存佈局

指針壓縮概要

  • 64位平臺上默認打開
  • 使用-XX:+UseCompressedOops壓縮對象指針 "oops"指的是普通對象指針("ordinary" object pointers)。 Java堆中對象指針會被壓縮成32位。 使用堆基地址(如果堆在低26G內存中的話,基地址爲0)

  • 使用-XX:+UseCompressedClassPointers選項來壓縮類指針

  • 對象中指向類元數據的指針會被壓縮成32位

  • 類指針壓縮空間會有一個基地址

元空間和類指針壓縮空間的區別

  • 類指針壓縮空間只包含類的元數據,比如InstanceKlass, ArrayKlass 僅當打開了UseCompressedClassPointers選項才生效 爲了提高性能,Java中的虛方法表也存放到這裏 這裏到底存放哪些元數據的類型,目前仍在減少

  • 元空間包含類的其它比較大的元數據,比如方法,字節碼,常量池等。

元空間的調優

使用-XX:MaxMetaspaceSize參數可以設置元空間的最大值,默認是沒有上限的,也就是說你的系統內存上限是多少它就是多少。-XX:MetaspaceSize選項指定的是元空間的初始大小,如果沒有指定的話,元空間會根據應用程序運行時的需要動態地調整大小。

MaxMetaspaceSize的調優

  • -XX:MaxMetaspaceSize={unlimited}
  • 元空間的大小受限於你機器的內存
  • 限制類的元數據使用的內存大小,以免出現虛擬內存切換以及本地內存分配失敗。如果懷疑有類加載器出現泄露,應當使用這個參數;32位機器上,如果地址空間可能會被耗盡,也應當設置這個參數。
  • 元空間的初始大小是21M——這是GC的初始的高水位線,超過這個大小會進行Full GC來進行類的回收。
  • 如果啓動後GC過於頻繁,請將該值設置得大一些
  • 可以設置成和持久代一樣的大小,以便推遲GC的執行時間

CompressedClassSpaceSize的調優

  • 只有當-XX:+UseCompressedClassPointers開啓了纔有效
  • -XX:CompressedClassSpaceSize=1G
  • 由於這個大小在啓動的時候就固定了的,因此最好設置得大點。
  • 沒有使用到的話不要進行設置
  • JVM後續可能會讓這個區可以動態的增長。不需要是連續的區域,只要從基地址可達就行;可能會將更多的類元信息放回到元空間中;未來會基於PredictedLoadedClassCount的值來自動的設置該空間的大小

元空間的一些工具

  • jmap -permstat改成了jmap -clstats。它用來打印Java堆的類加載器的統計數據。對每一個類加載器,會輸出它的名字,是否存活,地址,父類加載器,以及它已經加載的類的數量及大小。除此之外,駐留的字符串(intern)的數量及大小也會打印出來。
  • jstat -gc,這個命令輸出的是元空間的信息而非持久代的
  • jcmd GC.class_stats提供類元數據大小的詳細信息。使用這個功能啓動程序時需要加上-XX:+UnlockDiagnosticVMOptions選項。

提高GC的性能

如果你理解了元空間的概念,很容易發現GC的性能得到了提升。

  • Full GC中,元數據指向元數據的那些指針都不用再掃描了。很多複雜的元數據掃描的代碼(尤其是CMS裏面的那些)都刪除了。
  • 元空間只有少量的指針指向Java堆。這包括:類的元數據中指向java/lang/Class實例的指針;數組類的元數據中,指向java/lang/Class集合的指針。
  • 沒有元數據壓縮的開銷
  • 減少了根對象的掃描(不再掃描虛擬機裏面的已加載類的字典以及其它的內部哈希表)
  • 減少了Full GC的時間
  • G1回收器中,併發標記階段完成後可以進行類的卸載

總結

  • Hotspot中的元數據現在存儲到了元空間裏。mmap中的內存塊的生命週期與類加載器的一致。
  • 類指針壓縮空間(Compressed class pointer space)目前仍然是固定大小的,但它的空間較大
  • 可以進行參數的調優,不過這不是必需的。
  • 未來可能會增加其它的優化及新特性。比如, 應用程序類數據共享;新生代GC優化,G1回收器進行類的回收;減少元數據的大小,以及JVM內部對象的內存佔用量。

轉載:原文鏈接

發佈了48 篇原創文章 · 獲贊 10 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章