java.lang.OutOfMemoryError:Metaspace表示为java类元数据分配的本机内存量已过测试。让我们看看如何在独立应用程序和云应用程序中解决这个问题。
在Java 8及更高版本中,默认情况下为Java类分配的最大内存量(MaxMetaspaceSize)是无限,因此在大多数情况下无需更改此设置。另一方面,如果要限制为Java类分配的内存量,可以按如下方式设置:
java -XX:MaxMetaspaceSize=3200m
问题是-XX:MaxMetaspaceSize只是一个上限。当前的元空间大小(即已提交)将更小。事实上,有一个名为MaxMetaspaceFreeRatio的设置(默认为70%),这意味着实际的metaspace大小永远不会超过其占用率的230%。
要使其增长,首先必须填满,强制垃圾收集以释放对象,只有当它无法达到其MinMetaspaceFreeRatio(默认40%)目标时,才会扩展当前的元空间。然而,这不能超过GC循环后占用率的230%。
通过增加属性MaxMetaspaceSize的上限,您很可能解决这个问题。如果您可以在应用程序启动时看到错误,那么这是正确的。
另一方面,如果您在运行时看到此错误,建议在盲目增加MaxMetaspaceSize之前调查问题的根本原因。
为了找到根本原因,我们建议您遵循以下步骤:
1.了解JVM如何管理MetaSpace数据
1.了解如何在运行的Java应用程序中监视MetaSpace
1.检查应用程序的堆转储以查找有问题的类
Java热点按如下方式管理元数据空间:首先,JVM向操作系统请求一定数量的空间。然后,这个空间被划分为块。类加载器从其块中为元数据分配空间。
类元数据在卸载相应的Java类并回收其块以供重用或返回给操作系统时被释放。Java类作为垃圾收集的结果被卸载,为了卸载类和释放类元数据,可能会触发垃圾收集。当为类Metadata提交的空间达到某个阈值(高水位线)时,就会发生垃圾回收。
垃圾收集之后,高水位线可能会根据类Metadata释放的空间量而变化。
监视MetaSpace大小的最简单方法是使用JDK中提供的jstat工具。与选项**-gcmetacapacity**一起使用时,它提供以下信息:
jstat -gcmetacapacity (PID)
例如:
MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT CGC CGCT
0.0 374784.0 140360.0 0.0 253952.0 21168.0 23 0 0.000 6 0.046
以下是标签说明:
其他有趣的选项包括参数**-gcutil**:
$ jstat -gcutil (PID) | awk '{print($5)}'
这将以空间当前容量的百分比打印元空间利用率。
监控MetaSpace使用情况的另一个选项是JVM参数NativeMemoryTracking,您可以将其添加到启动参数中。例如:
-XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=detail -XX:+PrintNMTStatistics
启用本机内存跟踪时,可以使用以下命令请求JVM内存使用情况报告:
$ jcmd <pid> VM.native_memory
如果检查jcmd输出,您将在底部的Internal(committed)部分中找到已提交的本机内存量
Total: reserved=1334532KB, committed=369276KB
- Java Heap (reserved=524288KB, committed=132096KB)
(mmap: reserved=524288KB, committed=132096KB)
- Class (reserved=351761KB, committed=112629KB)
(classes #19111)
( instance classes #17977, array classes #1134)
(malloc=3601KB #66765)
(mmap: reserved=348160KB, committed=109028KB)
( Metadata: )
( reserved=94208KB, committed=92824KB)
( used=85533KB)
( free=7291KB)
( waste=0KB =0.00%)
( Class space:)
( reserved=253952KB, committed=16204KB)
( used=12643KB)
( free=3561KB)
( waste=0KB =0.00%)
在以Metaspace开头的行中,查找used值。这是JVM用于加载类的空间量。committed值是可用于块的空间量。reserved值是为元数据保留(但不一定提交)的空间量。
要深入了解MetaSpace错误,您应该检查Java应用程序的堆。您可以使用jmap命令行触发堆转储:
jmap -dump:format=b,file=dump.hprof <PID>
然后,使用您喜爱的工具打开堆转储。例如Eclipse MAT:
从堆转储中,可以查找重复的类,尤其是那些加载应用程序类的类。
最简单的方法是使用OQL控制台在OQL控制台中,您可以执行OQL查询来对类执行特别分析。例如,通过执行以下查询,可以从每个Classloader加载一个类列表:
select map(sort(map(heap.objects('java.lang.ClassLoader'), '{loader: it, count: it.classes.elementCount }'), 'lhs.count < rhs.count'), 'toHtml(it) + "
"')
这可以作为判断Classloader是否正在加载增量的宝贵提示
在OpenShift/Kubernetes上使用OpenJDK映像时,Metaspace的默认最大值为XX:MaxMetaspaceSize=100m。您可能已经注意到,通过JAVA_OPTIONS环境变量设置此值不起作用,因为默认值附加在底部:
VM Arguments: -Xms128m -Xmx1024m -XX:MetaspaceSize=128M -XX:MaxMetaspaceSize=256m -XX:AdaptiveSizePolicyWeight=90 -XX:MaxMetaspaceSize=100m -XX:+ExitOnOutOfMemoryError
设置MaxMetaspaceSize的正确方法是通过GC_MAX_METASPACE_SIZE环境变量。例如,如果您正在使用展开。使用JKube部署应用程序的yaml文件,以下设置将覆盖MaxMetaspaceSize和MaxMetasaceSize的默认值:
spec:
template:
spec:
containers:
- env:
- name: JAVA_OPTIONS
value: '-Xms128m -Xmx1024m'
- name: GC_MAX_METASPACE_SIZE
value: 256
- name: GC_METASPACE_SIZE
value: 96
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : http://www.mastertheboss.com/java/solving-java-lang-outofmemoryerror-metaspace-error/
内容来源于网络,如有侵权,请联系作者删除!