您可能已經知道,現在可以下載JDK 8 Early Access 。 這使Java開發人員可以嘗試Java 8的一些新語言和運行時功能。這些功能之一是完全刪除自Oracle自JDK 7發行以來就宣布的Permanent Generation(PermGen)空間。例如,自JDK 7起,它已從PermGen空間中刪除。JDK8版本完成了其退役工作。 本文將分享我們到目前為止在PermGen后繼者Metaspace上找到的信息。 當執行Java程序“泄漏”類元數據對象時,我們還將比較HotSpot 1.7與HotSpot 1.8(b75)的運行時行為。 Java 8正式發布后,有關Metaspace的最終規范,調整標志和文檔應可用。
元空間:
新的存儲空間誕生了
現在,JDK 8 HotSpot JVM使用本機內存來表示類元數據,這稱為元空間。 類似于Oracle JRockit和IBM JVM的 。 好消息是,它不再意味著java.lang.OutOfMemoryError:PermGen空間問題,也不再需要調整和監視此內存空間……不是那么快。 雖然此更改默認情況下是不可見的,但接下來我們將向您顯示,您仍然需要擔心類元數據的內存占用。 還請記住,此新功能不能神奇地消除類和類加載器的內存泄漏。 您將需要使用其他方法并通過學習新的命名約定來跟蹤這些問題。 我建議您閱讀PermGen刪除摘要和Jon對此主題的評論 。
綜上所述:
PermGen空間狀況
- 此內存空間已完全刪除。
- PermSize和MaxPermSize JVM參數將被忽略,如果在啟動時出現警告,則會發出警告。
元空間內存分配模型
- 現在,類元數據的大多數分配都是在本機內存之外分配的。
- 用來描述類元數據的分類器已被刪除。
元空間容量
- 默認情況下,類元數據分配受可用本機內存量限制(容量將取決于您是否使用32位JVM與64位以及操作系統虛擬內存的可用性)。
- 一個新的標志(MaxMetaspaceSize)可用,允許您限制用于類元數據的本機內存量。 如果不指定此標志,則Metaspace將在運行時根據應用程序需求動態調整大小。
元空間垃圾收集
- 一旦類元數據使用量達到“ MaxMetaspaceSize”,就會觸發死類和類加載器的垃圾收集。
- 為了限制此類垃圾收集的頻率或延遲,顯然將需要對Metaspace進行適當的監視和調整。 過多的Metaspace垃圾回收可能是類的征兆,類裝入器的內存泄漏或應用程序的大小不足。
Java堆空間影響
- 一些其他數據已移至Java堆空間。 這意味著在將來的JDK 8升級之后,您可能會發現Java堆空間的增加。
元空間監控
- HotSpot 1.8詳細GC日志輸出中提供了元空間用法。
- 根據我們對b75的測試,此時Jstat和JVisualVM尚未更新,并且仍然存在舊的PermGen空間引用。
現在有足夠的理論,讓我們通過泄漏的Java程序來了解這種新的內存空間在起作用……
PermGen與Metaspace運行時比較
為了更好地理解新的Metaspace內存空間的運行時行為,我們創建了一個泄漏Java程序的類元數據。 您可以在此處下載源代碼。
將測試以下方案:
- 為了監視和耗盡設置為128 MB的PermGen內存空間,請使用JDK 1.7運行Java程序。
- 使用JDK 1.8(b75)運行Java程序,以便監視新Metaspace內存空間的動態增加和垃圾回收。
- 使用JDK 1.8(b75)運行Java程序,以通過將MaxMetaspaceSize值設置為128 MB來模擬元空間的耗盡。
JDK 1.7 @ 64位– PermGen耗盡
- 具有50K配置的迭代的Java程序
- Java堆空間為1024 MB
- Java PermGen空間為128 MB(-XX:MaxPermSize = 128m)
從JVisualVM可以看到,在加載大約30K +類后,達到了PermGen耗盡。 我們還可以從程序和GC輸出中看到這種消耗。
Class metadata leak simulatorAuthor: Pierre-Hugues Charbonneauhttp://javaeesupportpatterns.blogspot.comERROR: java.lang.OutOfMemoryError: PermGen space
現在,讓我們使用HotSpot JDK 1.8 JRE執行該程序。
JDK 1.8 @ 64位– Metaspace動態調整大小
- 具有50K配置的迭代的Java程序
- Java堆空間為1024 MB
- Java Metaspace空間:無界(默認)
從詳細的GC輸出中可以看到,JVM Metaspace確實從20 MB擴展到了328 MB的保留本機內存,以適應Java程序中增加的類元數據內存占用量。 我們還可以觀察到JVM試圖破壞任何無效類或類加載器對象的垃圾回收事件。 由于我們的Java程序正在泄漏,因此JVM除了動態擴展Metaspace內存空間外別無選擇。 該程序能夠在沒有OOM事件的情況下運行其50K迭代,并加載了50K +類。 讓我們轉到最后一個測試場景。
JDK 1.8 @ 64位–元空間耗盡
- 具有50K配置的迭代的Java程序
- Java堆空間為1024 MB
- Java元空間空間:128 MB(-XX:MaxMetaspaceSize = 128m)
從JVisualVM可以看到,在加載大約30K +類之后達到了元空間消耗; 與JDK 1.7的運行非常相似。 我們還可以從程序和GC輸出中看到這一點。 另一個有趣的發現是保留的本機內存占用空間是指定的最大大小的兩倍。 如果可能的話,這可能表明有些機會可以微調元空間重新調整大小的策略,以避免本機內存浪費。
現在在下面找到我們從Java程序輸出中獲得的Exception。
Class metadata leak simulatorAuthor: Pierre-Hugues Charbonneauhttp://javaeesupportpatterns.blogspot.comERROR: java.lang.OutOfMemoryError: Metadata space
做完了!
不出所料,像我們使用JDK 1.7進行基線運行一樣,將Metaspace的上限限制為128 MB,這使我們無法完成程序的50K迭代。 JVM引發了一個新的OOM錯誤。 內存分配失敗后,JVM從元空間引發了上述OOM事件。
#metaspace.cpp
最后的話
希望您對此早期分析和使用新的Java 8 Metaspace進行試驗表示贊賞。 當前的觀察結果明確表明,將需要進行適當的監視和調整,才能避免出現諸如上一次測試場景中觸發的過多Metaspace GC或OOM條件之類的問題。 未來的文章可能會包括性能比較,以識別與此新功能相關的潛在性能改進。
參考: Java 8: Java EE支持模式和Java教程博客中的JCG合作伙伴 Pierre-Hugues Charbonneau 從PermGen到Metaspace 。
翻譯自: https://www.javacodegeeks.com/2013/02/java-8-from-permgen-to-metaspace.html