[英]java8 “java.lang.OutOfMemoryError: Metaspace”
在將我們的 Java 應用程序(在 Tomcat 上運行的服務)JRE 從 Java 7 切換到 Java 8 后,我們開始看到java.lang.OutOfMemoryError: Metaspace
在高流量運行幾天后。
堆使用正常。 在性能測試期間執行相同的代碼流一段時間后,元空間會跳轉。
元空間內存問題的可能原因是什么?
當前設置是:
-server -Xms8g -Xmx8g -XX:MaxMetaspaceSize=3200m -XX:+UseParNewGC
-XX:+UseConcMarkSweepGC -XX:MaxGCPauseMillis=1000
-XX:+DisableExplicitGC -XX:+PrintGCDetails
-XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=7 -XX:NewSize=5004m
-XX:MaxNewSize=5004m -XX:MaxTenuringThreshold=12
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintFlagsFinal
-XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution
-XX:+PrintGCCause -XX:+PrintAdaptiveSizePolicy
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 -XX:GCLogFileSize=200M
此外,該應用程序大量使用反射。 我們還使用自定義類加載器。 所有這些都在 java 7 中正常工作。
我假設您可以在一段時間內使用相同的請求(請求集)創建問題。 定義 MaxMetaspaceSize 是一件好事,否則應用程序將使用本機內存,直到它用完為止。 但我將從以下步驟開始:
-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -XX:+UnlockDiagnosticVMOptions
一旦將visualvm(jvisualvm)連接到JVM,點擊monitor,然后查看加載的類的數量。 在那里您可以監視堆以及元空間。 但我會添加其他工具來密切監視元空間。
select map(sort(map(heap.objects('java.lang.ClassLoader'), '{loader: it, count: it.classes.elementCount }'), 'lhs.count < rhs.count'), 'toHtml (它) + "
"')
但是上面名為“類加載器加載的類”的查詢會很慢,它實際上會顯示每個類加載器加載的類。
select { loader: cl,
classes: filter(map(cl.classes.elementData, 'it'), 'it != null') }
from instanceof java.lang.ClassLoader cl
JMC
連接到虛擬機,然后在連接后單擊右上角的 JMC 中的“診斷命令”。 由於我們啟用了 UnlockDiagnosticVMOptions ,因此可以執行 GC.class_stats 。 您可能希望通過顯示所有列運行它並在 csv 中打印。 所以命令看起來像:
GC.class_stats -all=true -csv=true
然后你可以比較不同時期的類統計數據,找出哪些類導致問題(元空間增長)或哪些類在元空間中有相關信息(方法/方法數據)。 如何分析當時收集的 csv 輸出:好吧,我會將該 csv 加載到數據庫或其他地方的兩個類似表(代表 csv)中,以比較 GC.class_stats csv 輸出,我可以在其中運行一些 SQL 或任何其他分析工具。 這樣可以更好地了解元空間中究竟增長了什么。 GC 類統計信息包含以下列:
指數,超級,InstSize,InstCount,InstBytes,鏡子,KlassBytes,K_secondary_supers,VTab,ITAB,OopMap,IK_methods,IK_method_ordering,IK_default_methods,IK_default_vtable_indices,IK_local_interfaces,IK_transitive_interfaces,IK_fields,IK_inner_classes,IK_signers,class_annotations,class_type_annotations,fields_annotations,fields_type_annotations,methods_annotations, methods_parameter_annotations,methods_type_annotations,methods_default_annotations,annotations,Cp,CpTags,CpCache,CpOperands,CpRefMap,CpAll,MethodCount,MethodBytes,ConstMethod,MethodData,StackMap,Bytecodes,MethodAll,ROAll,RWAll,Loader,ClassName,Class
希望它有幫助。 此外,如果它不會在 1.7 中導致任何泄漏,則該錯誤可能出現在 Java 8 中。
如果任何人持有對類加載器的任何引用,這些類也不會從元空間中卸載。 如果你知道你的類加載器應該被 GC 並且沒有人應該持有對你的類加載器的引用,你可以回到visualvm 中的堆轉儲並單擊類加載器實例並右鍵單擊以找到“最近的 GC 根”,它會告訴你您持有對類加載器的引用。
我們遇到了類似的問題,根本原因是 60K 類文件被加載到元空間內存中,但沒有被卸載。在 JVM arg 下面添加修復了問題。
-Dcom.sun.xml.bind.v2.bytecode.ClassTailor.noOptimize=true
https://issues.apache.org/jira/browse/CXF-2939
希望這會有所幫助。
在將Java應用程序(在Tomcat上運行的服務)的Java應用程序從Java 7切換到Java 8之后,在運行了幾天的高流量之后,我們開始看到java.lang.OutOfMemoryError: Metaspace
。
堆的使用還可以。 在性能測試期間執行相同代碼流之后的某個時間之后,元空間會跳轉。
元空間內存問題的可能原因是什么?
當前設置為:
-server -Xms8g -Xmx8g -XX:MaxMetaspaceSize=3200m -XX:+UseParNewGC
-XX:+UseConcMarkSweepGC -XX:MaxGCPauseMillis=1000
-XX:+DisableExplicitGC -XX:+PrintGCDetails
-XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=7 -XX:NewSize=5004m
-XX:MaxNewSize=5004m -XX:MaxTenuringThreshold=12
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintFlagsFinal
-XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution
-XX:+PrintGCCause -XX:+PrintAdaptiveSizePolicy
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=3 -XX:GCLogFileSize=200M
該應用程序也大量使用反射。 此外,我們使用自定義類加載器。 他們都在Java 7中正常工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.