Permanent Generation Removal Overview(譯文)

英文原稿:http://vdisk.weibo.com/s/vxGdGZEZTEjkhtml

中文整理稿:http://it.deepinmind.com/gc/2014/05/14/metaspace-in-java-8.htmljava

其實上面的整理稿,是針對這篇英文文稿的翻譯兼整理,可是感受有點亂,有點強迫症,因此乾脆本身來翻譯。關於vm相關性能數據的監控部分略掉了,此稿件主要是介紹perm gen的設計與移除,以及移除perm gen以後新的內存模型,因此後面關於內存的調優還有性能的監測都過於簡單,若是想了解,能夠去看周志明先生的《深刻理解Java虛擬機》,裏面對jstat等工具備更多的介紹。web

翻譯:數組

    Oracle HotSpot JVM中的perm gen保存了HotSpot用於描述Java對象(Java objects)的元數據(metadata)。perm gen在Full GC中會和Java堆(Java Heap)一塊兒經歷垃圾回收。perm gen在JDK8中的HotSpot中,已經被移除了。本節簡單的描述了perm gen及移除它的動機。還討論了移除perm gen可能對Java程序的執行形成的多方面的影響。數據結構

 

 

議題併發

  • 什麼是perm gen
  • 如今的元數據在哪兒
  • 壓縮的類指針
  • 新的調節參數
  • Memory Pool MXBeans

 

什麼是perm gen函數

  • 全名permanent generation
  • 是Java Heap中用於存儲虛擬機類的元數據的區域
  • Java類在HotSpot中的內在表現
    • 類的結構信息,字段,名字
    • 方法的彙編信息和字節碼
    • Vtables(虛函數表)
    • 常量池和符號解析

 

含有perm gen的vm內存分佈示意圖:工具

 

 

PermGen 大小oop

  • 1.受限於參數MaxPermSize(默認是64M-85M)
  • 2.須要Java Heap中連續的存儲空間:若是分配的堆空間不連續,那麼從old gen和perm gen定位指向新對象的引用,代價就會更大,並且也會更復雜。(card table   remembered set)
  • 3.一旦耗盡,就會拋異常
    • 清除引用來觸發類卸載
    • 配置更大的MaxPermSize
  • 4.perm gen的大小依賴於類的數量,方法的大小,以及常量池的大小

 

 

爲何要移除PermGen性能

  • 啓動的時候就要指定大小,難以調優:MaxPermSize要設多大?
  • HotpSpot內部類型是Java對象,可能會在Full GC中移動,對應用程序來講,不透明,而且非強類型,很難調試,須要用於存儲元數據的空間
  • 簡化Full GC
    • 爲每一個收集器的元數據指定迭代器
  • 但願能併發的回收類型數據空間,而不是在GC停頓期間
  • 使受限於permgen的將來的改進成爲可能

 

元數據去哪兒了?

 

 

得益於Java語言特性:類及相關元數據的生命週期和累加載器相匹配

 

每個加載器的存儲空間

  • 僅線性分配
  • 沒有單獨的回收(除非RedefineClasses和類加載失敗)
  • 沒有GC掃描和整理
  • 不須要從新安置元數據空間對象
  • 當GC發現類加載器死亡,則整個空間一塊兒回收

 

這些存儲空間的集體稱爲Metaspace

 

 

Metaspace 分配

  • 爲元數據分配多個映射虛擬內存空間
  • 爲每一個類加載器分配塊狀空間列表
    • 塊的大小依賴於類加載器的大小
    • 爲sun/reflect/DelegatingClassLoader, JSR292匿名類的加載器分配較小的塊
  • 歸還內存塊,以釋放塊狀列表
  • 當被清空的時候,歸還虛擬內存空間
  • 設計諸多策略來減小碎片

 

以下圖:

 

(圖中CL爲類加載器,Boot CL爲啓動類加載器,vs1,vs2,vs3爲虛擬內存空間,黃色的塊爲元數據塊)

 

Java對象內存分配

 

堆上對象有指向Metaspace中本身類信息的指針—>_klass

在64位平臺上,爲了壓縮JVM對象中的類指針,引入了「壓縮類指針空間」(對象中的_klass變爲4字節,指向壓縮類空間中的數據,該數據再指向Metaspace中的類信息)

 

 

壓縮指針(壓縮類指針,壓縮對象指針)

  • 默認是爲了64位平臺
  • 使用-XX:+UseCompressedOops 來壓縮對象指針
    • oops是指普通對象指針
    • Java堆中對象的對象指針被壓縮到32bit
    • 使用堆基地址(若是在低26G內存空間中,爲0)即,指針的偏移量針對於堆的基地址 
  • 使用-XX:+UseCompressedClassPointers 壓縮類指針
    • 對象的類指針(_klass)被壓縮至32bit
    • 使用類指針壓縮空間的基地址

Metaspace與類壓縮空間的對比

  • 類壓縮空間只包含像接口指針(InstanceKlass),數組指針(ArrayKlass)等元數據
    • 僅當UseCompressedClassPointers爲true的時候會這樣
    • 爲了性能問題,這裏還保存了Java 虛方法表
    • 咱們仍然在減小這個元數據類型 
  • 而Metaspace包含了元數據的其餘全部的數據,這可能比較大,如方法,字節碼,常量池

GC性能的提高

  • 在Full GC,元數據到元數據的指針不須要掃描
    • 一大堆元數據掃描的複雜代碼(尤爲在CMS)都被刪除了
  • 元數據空間包含較少的指向Java Heap的指針
    • 指向java/lang/Class對象的指針存儲在類元數據中
    • 數據類元數據中,有指向其成員類Class對象的指針
    • 咱們要移除這些 
  • 元數據再也不有整理消耗
  • 減小了根掃描(不掃描VM已加載類的字典和其餘內部的哈希表)
  • Full GC的時間將會縮短(不一樣狀況下可能會有所不一樣)
  • 在G1中能夠在併發標記以後進行類卸載
  • 能夠調優

 

調優標誌

MaxMetaspaceSize

 

  • -XX:MaxMetaspaceSize={unlimited}
  • Metaspace受機器內存的限制
  • 在虛擬內存切換頻繁和本地內存分配失敗以前,限制類元數據使用的內存
    • 若是類加載器內存可能泄漏
    • 若是在32位平臺上,地址空間可能耗盡
  • MaxMetaspaceSize是指Metaspace和壓縮類指針空間的總和 

MetaspaceSize

  • 初始大小爲21mb,超過這個值,將進行Full GC來回收類
    • GC的相關操做用於檢測已死的類加載器,和未加載的類
  • 若是在啓動階段發生了過多的GC,則須要設置一個高點的限制
  • 可使用與PermSize相同的值,來延緩初始GC
  • 在下次Metaspace GC以前,High water mark會隨着接下來合理數量的頭空間的收集而增高

CompressedClassSpaceSize

  • 當使用了-XX:+UseCompressedClassPointers 纔有效
  • -XX:CompressedClassSpaceSize=1G 
  • 由於這個空間只能在啓動的時候設置,因此一開始就設置大一點
  • 不使用的時候,不會分配
  • 將來的工做,是要使這塊空間可增加
    • 不須要連續,只須要從基地址可達
    • 更傾向於將更多的類元數據移到Metaspace中 
  • 將來可能會以性能爲主導
    • PredictedLoadedClassCount (該標誌目前處於試驗性):用於設置其餘JVM內部數據結構的大小,像已加載類的字典
  • 開發者可能會發現對於CompressedClassSpaceSize和UseCompressedClassPointers的不一樣命名。但在JDK-8015107中已經設定,對metaspace的概念,須要使用統一的命名方式

 

能夠經過-XX:+PrintGCDetails and -XX:+PrintHeapAtGC來查看metaspace的使用狀況

 

PermGen內存池之前在內存管理中屬於Heap內存池的列表中,如今移除了

 

總結:

  • HotSpot 元數據如今存在元空間中
    • 壓縮類指針空間仍然須要被設定,可是要大一些
  • 有調優標誌,雖然並非必需要使用的
  • 這種改變使得其餘優化與特性成爲可能
    • 共享類數據
    • 新生代優化,G1進行類卸載
    • 元數據減小

 

 

譯者有話說:

 

表示有些地方,我沒看懂,不過總的仍是有收穫的。並且,我感受是指導性文檔,摳字眼就不必了。最近一直在看JVM的相關內容,總結一句話,發展時間過久,各類詞彙亂用,致使哪哪兒都模棱兩可。

好比,如今從一些較官方的文檔來看,Java Heap和咱們常說的java堆是不一樣的,咱們常說的java堆只包含新生代和老年代,是用來存儲對象實例數據的,可是Java Heap是包括perm gen在內的GC做用的整個堆空間。有人說,這有神馬影響嗎?沒影響的時候沒影響,有影響的時候,真是搞腦子。

 

簡單點歸納

 

過去類的元數據存儲在perm gen,做爲Java Heap的一部分,使用instanceKlass,instanceKlassKlass,klassKlass(詳見R大關於perm gen數據的追蹤博客),接受GC傳統意義上的掃描。弊端:內存受限,容易溢出;空間回收性能低等。如今的元數據存在元空間中。元空間由多個虛擬內存空間構成,每一個虛擬內存空間又被劃分爲不一樣大小的塊。以類加載器爲源頭,隨着類的不斷加載,不斷從虛擬內存空間中分配塊空間,從而使每一個類加載器對應了一個塊列表。當GC檢測到某個類加載器已死,就總體釋放整個列表,回收內存。

 

至於壓縮類空間,出於多個緣由考慮,主要有兩個。第一,在64位平臺,指針膨脹致使內存浪費,使用壓縮類指針,壓縮類指針空間基地址的概念,繼續使用32位指針尋址;第二,這樣一個空間還能夠存儲部分元數據,以提升相應性能。

相關文章
相關標籤/搜索