java8 去掉 perm 用 Metaspace 來替代


詳見:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt266

 正如大家所知,JDK 8 Early Access版已經提供下載。這使開發者可以體驗Java8的新特性。其中之一,是Oracle從JDK7發布以來就一直宣稱的要完全移除永久代空間。例如,字符串內部池,已經在JDK7中從永久代中移除。JDK8的發布將宣告它的終結。這篇文章將會分享到目前為止對 PermGen 繼任者:Metaspace的了解。我們將通過運行一個存在類元數據對象“泄漏”的程序,來對比HotSpot1.7與HotSpot1.8(b75,譯者注:翻譯文章時已經到b118)的運行時行為。待Java 8 正式發布之后,才會提供最終的規范,優化參數和相關文檔。

元空間(Metaspace):

一種新的內存空間的誕生

    JDK8 HotSpot JVM 使用本地內存來存儲類元數據信息並稱之為:元空間(Metaspace);這與Oracle JRockit 和IBM JVM’s很相似。這將是一個好消息:意味着不會再有java.lang.OutOfMemoryError: PermGen問題,也不再需要你進行調優及監控內存空間的使用……但請等等,這么說還為時過早。在默認情況下,這些改變是透明的,接下來我們的展示將使你知道仍然要關注類元數據內存的占用。請一定要牢記,這個新特性也不能神奇地消除類和類加載器導致的內存泄漏。你需求使用不同的方法以及遵守新的命名約定來追蹤這些問題。我推薦大家閱讀有關PermGen移除總結和Jon對此的評論。

    總結如下:

PermGen 空間的狀況

  • 這部分內存空間將全部移除。

  • JVM的參數:PermSize 和 MaxPermSize 會被忽略並給出警告(如果在啟用時設置了這兩個參數)。

 

Metaspace 內存分配模型

 

  • 大部分類元數據都在本地內存中分配。

  • 用於描述類元數據的“klasses”已經被移除。

 

Metaspace 容量

 

  • 默認情況下,類元數據只受可用的本地內存限制(容量取決於是32位或是64位操作系統的可用虛擬內存大小)。

  • 新參數(MaxMetaspaceSize)用於限制本地內存分配給類元數據的大小。如果沒有指定這個參數,元空間會在運行時根據需要動態調整。

Metaspace 垃圾回收

  • 對於僵死的類及類加載器的垃圾回收將在元數據使用達到“MaxMetaspaceSize”參數的設定值時進行。

  • 適時地監控和調整元空間對於減小垃圾回收頻率和減少延時是很有必要的。持續的元空間垃圾回收說明,可能存在類、類加載器導致的內存泄漏或是大小設置不合適。

Java 堆內存的影響

  • 一些雜項數據已經移到Java堆空間中。升級到JDK8之后,會發現Java堆 空間有所增長。

Metaspace 監控

  • 元空間的使用情況可以從HotSpot1.8的詳細GC日志輸出中得到。

  • Jstat 和 JVisualVM兩個工具,在我們使用b75版本進行測試時,已經更新了,但是還是能看到老的PermGen空間的出現。

    前面已經從理論上充分說明,下面讓我們通過“泄漏”程序進行新內存空間的觀察……

PermGen vs. Metaspace 運行時比較

    為了更好地理解Metaspace內存空間的運行時行為,我們建立了一個類元數據泄漏程序。可以從此處下載源代碼。

    將進行以下幾種場景的測試:

  • 使用JDK1.7運行Java程序,監控並耗盡設定的128MB大小的PermGen內存空間。

  • 使用JDK1.8 (b75)運行Java程序,監控新Metaspace內存空間的動態增長和垃圾回收過程。

  • 使用JDK1.8 (b75)運行Java程序,模擬耗盡通過“MaxMetaspaceSize”參數設定的128MB大小的Metaspace內存空間。

JDK 1.7 @64-bit – PermGen 耗盡測試

  • Java程序中包括5萬次可配置迭代過程

  • Java堆大小為1024 MB

  • Java的PermGen空間為128 MB(-XX:MaxPermSize=128m)

    可以從上面的JVisualVM的截圖看出:當加載超過3萬個類之后,PermGen被耗盡。我們也能通過程序和GC的輸出觀察耗盡的過程。

copy在CODE上查看代碼片派生到我的代碼片

  1. Class metadata leak simulator  

  2. Author: Pierre-Hugues Charbonneau  

  3. http://javaeesupportpatterns.blogspot.com  

  4. ERROR: java.lang.OutOfMemoryError: PermGen space  

 

    下面我們使用HotSpot JDK 1.8 JRE來執行程序。

JDK 1.8 @64-bit – Metaspace大小動態調整測試

  • Java程序中包括5萬次可配置迭代過程

  • Java堆大小為1024 MB

  • Java的Metaspace空間:不受限制 (默認)

    從上面的截圖可以看到詳細的GC輸出日志,JVM Metaspace進行了動態擴展,本地內存的使用由20MB增長到328MB,以滿足程序中不斷增長的類數據內存占用需求。我們也能觀察到JVM的垃圾回收事件—試圖銷毀僵死的類或類加載器對象。但是,由於我們程序的泄漏,JVM別無選擇只能動態擴展Metaspace內存空間。程序能夠運行5萬次迭代,加載超過5萬個類,而沒有出現OOM事件。下面繼續進行最后的一個測試場景:

JDK 1.8 @64-bit – Metaspace depletion

  • Java程序中包括5萬次可配置迭代過程

  • Java堆大小為1024 MB

  • Java的Metaspace空間:128MB(-XX:MaxMetaspaceSize=128m)

    可以從上面的JVisualVM的截圖看出:當加載超過3萬個類之后,Metaspace被耗盡;與JDK1.7運行時非常相似。我們也能通過程序和GC的輸出觀察耗盡的過程。另一個有趣的現象是,保留的原生內存占用量是設定的最大大小兩倍之多。這可能表明,如果可能的話,可微調元空間容量大小策略,來避免本地內存的浪費。

    從Java程序的輸出中看到如下異常。

 

[html] view plaincopy在CODE上查看代碼片派生到我的代碼片

  1. Class metadata leak simulator  

  2. Author: Pierre-Hugues Charbonneau  

  3. http://javaeesupportpatterns.blogspot.com  

  4. ERROR: java.lang.OutOfMemoryError: Metadata space  

 

    完成!

    正如預期的那樣,像運行JDK1.7基線時一樣,限定128 MB大小元空間時,並不能讓程序完成50萬次迭代。一種新的OOM錯誤被JVM拋出。上述OOM事件,是由於元空間內存分配失敗由JVM拋出的。

#metaspace.cpp

結束語

    我希望您能喜歡這篇較早的對Java8元空間的分析和實驗文章。目前的觀察有力地表明,適當的監控和調優是必須的,以此來避免諸如,過度的在元空間中的GC,或像我們測試場景下觸發OOM的條件。后面的文章中可能包括,性能上的比較,以確定這一新特性是否有潛在的性能上的提升。

 

    參考:Java 8: From PermGen to Metaspace from ourJCG partner Pierre-Hugues Charbonneau at theJava EE Support Patterns & Java Tutorialblog.


免責聲明!

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



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