你注意到了嗎?JDK 8早期可訪問版本已經提供下載了,java 開發人員可以使用java 8 提供的新的語言和運行特性來做一些實驗。其中一個特性就是完全的移除永久代(Permanent Generation (PermGen)),這從JDK 7開始Oracle就開始行動了,比如:本地化的String從JDK 7開始就被移除了永久代(Permanent Generation )。JDK 8讓它最終退役了。 本文將會分享至今為至我收集的關於永久代(Permanent Generation )的替代者:元空間(Metaspace)的信息。我也會比較在執行JAVA 程序時HotSpot 1.7 和 HotSpot 1.8 (b75)的運行行為。 關於元空間(Metaspace)最后的規范、調整參數和文檔將在Java 8 正式發布之后公開。 元空間(Metaspace):一個新的內存空間的誕生 與 Oracle JRockit 和 IBM JVM類似,JDK 8.HotSpot JVM開始使用本地化的內存存放類的元數據,這個空間叫做元空間(Metaspace)。 一 個好的消息是意味着java.lang.OutOfMemoryError: PermGen的空間問題將不復存在,並且不再需要調整和監控這個內存空間,雖然還沒有那么快。當這個變化被默認執行的時候,我們會發現你任然需要擔心類的元數據的內存占用率的問題,所以請記住這個新的特性並不會奇跡般的消除類和類加載器的內存泄漏。而是你需要使用一些不同的方式和學習新名詞來追查這些問題。 我建議你閱讀永久帶移除的總結和Jon對這個問題的意見。 總結: 永久區的情況: 這個內存空間被完全的移除 JVM參數PermSize 和 MaxPermSize會被忽略,當前在啟動時會有警告信息 元空間(Metaspace)內存分配模型 現在大多數的類元數據分配在本地化內存中。 我們用來描述類的元數據的klasses已經被移除。 元空間的容量 默認情況下,類元數據分配受到可用的本機內存容量的限制(容量依然取決於你使用32位JVM還是64位操作系統的虛擬內存的可用性)。 一個新的參數 (MaxMetaspaceSize)可以使用。允許你來限制用於類元數據的本地內存。如果沒有特別指定,元空間將會根據應用程序在運行時的需求動態設置大小。 元空間的垃圾回收 如果類元數據的空間占用達到參數“MaxMetaspaceSize”設置的值,將會觸發對死亡對象和類加載器的垃圾回收。 為了限制垃圾回收的頻率和延遲,適當的監控和調優元空間是非常有必要的。元空間過多的垃圾收集可能表示類,類加載器內存泄漏或對你的應用程序來說空間太小了。 java堆空間的影響 一些各種各樣的數據已經轉移到Java堆空間。這意味着未來的JDK8升級后,您可能會發現Java堆空間的不斷增加。 元空間監控 元空間的使用從HotSpot 1.8開始有詳細的GC日志輸出。 在我們基於B75測試的時候Jstat 和JVisualVM還沒有升級, 目前還是引用到老的永久代空間。現在有足夠的理論,我們可以通過我們的Java程序泄漏的行為來觀察我們的這個新的內存空間... 永久代和元空間運行時對照 為了更好的理解新的元空間運行時的行為特征,我們創建一個類元數據泄露的java程序,你可以在這里下載源代碼: 我們測試下面的場景: 使用JDK 1.7運行java程序,並且為了監控和耗盡永久代內存空間,將其設置為128MB 使用JDK1.8(B75)運行java程序,並且監控新的元空間內存的冬天增長和垃圾回收。 使用JDK1.8(B75)運行java程序,通過設置MaxMetaspaceSize 為128MB來同樣耗盡元空間 . JDK 1.7 @64-bit – PermGen depletion java程序設置50k次的迭代 java的堆空間為1024MB java的永久代空間為128MB (-XX:MaxPermSize=128m) 正如你看到的JVisualVM的報告,當加載30K+ 的類的時候,永久代被耗盡。我們也可以從程序和GC的輸出文件中發現耗盡。類元數據泄漏模擬器的作者Pierre-Hugues Charbonneau在博客: http://javaeesupportpatterns.blogspot.com中描述了錯誤: ERROR: java.lang.OutOfMemoryError: PermGen space 。現在我們使用 HotSpot JDK 1.8 JRE.來運行程序。 JDK 1.8 @64-bit – Metaspace dynamic re-size Java 程序設置50k次的迭代 Java 堆空間為1024MB Java 元空間為無限(默認值) 正如你看到的詳細的GC輸出,為了滿足我們的Java程序不斷增加的類元數據的內存占用,JVM元空間擴大從20 MB動態占用本機內存高達328 MB。我們也可以觀察垃圾收集,JVM在試圖摧毀任何死類或類加載器對象。自從我們的Java程序泄漏,JVM不得不擴張元空間的內存空間。 該方案可以迭代50K次,並且沒有OOM事件和加載50K+類。 接下去我們來看最后的測試場景: JDK 1.8 @64-bit – Metaspace depletion Java 程序設置50k次的迭代 Java 堆空間為1024MB Java 元空間為128 MB (-XX:MaxMetaspaceSize=128m) 正如你看到的JVisualVM的報告,當加載30K+ 的類的時候,元空間被耗盡,和在JDK1.7的表現非常相近。我們也可以在程序和GC的輸出日志中找到。另一個有趣的現象是,本機內存保留的占用空間是指定的最大大小的兩倍之多。如果可能的話,為了避免本機內存浪費。這可能表明需要優化元空間擴張尺寸的策略,。 現在我們可以從java程序的輸出日志中找到下面的異常: view sourceprint? 1. Class metadata leak simulator 2. Author: Pierre-Hugues Charbonneau 3.
http://javaeesupportpatterns.blogspot.com<;/a> 4. ERROR: java.lang.OutOfMemoryError: Metadata space 5. Done! 正如預期的那樣,設置元空間最大尺寸為128 MB,就像我們在JDK1.7中一樣沒有讓我們完成我們的50K迭代的計划。JVM拋出一個新的OOM錯誤。上述OOM事件是由JVM從元空間在捕獲一個一個內存分配失敗后拋出。 #metaspace.cpp 結束語 我希望你能欣賞這個對新的Java8元空間的早期的分析和實驗 。目前觀測表明,為了遠離類似在我們最后測試場景中出現的頻繁的元空間GC和OOM的問題,適當的監控和調優是必須的。以后的文章中可能包括性能比較,以確定這一新功能相關的潛在性能改進。請隨時提供任何意見。