解决java.lang.OutOfMemoryError:Metaspace error

x33g5p2x  于2022-10-15 转载在 Java  
字(3.2k)|赞(0)|评价(0)|浏览(2896)

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热点如何管理MetaSpace数据

Java热点按如下方式管理元数据空间:首先,JVM向操作系统请求一定数量的空间。然后,这个空间被划分为。类加载器从其块中为元数据分配空间。

类元数据在卸载相应的Java类并回收其块以供重用或返回给操作系统时被释放。Java类作为垃圾收集的结果被卸载,为了卸载类和释放类元数据,可能会触发垃圾收集。当为类Metadata提交的空间达到某个阈值(高水位线)时,就会发生垃圾回收。
垃圾收集之后,高水位线可能会根据类Metadata释放的空间量而变化。

使用jstat监视MetaSpace

监视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

以下是标签说明:

  • MCMN:最小亚空间容量(kB)。
  • MCMX:最大元空间容量(kB)。
    *MC:元空间容量(kB)
  • CCSMN:压缩类空间最小容量(kB)。
  • CCSMX:压缩类空间最大容量(kB)。
  • YGC:年轻一代GC事件的数量。
  • FGC:完整GC事件数。
  • FGCT:完全垃圾收集时间。
  • GCT:总垃圾收集时间。

其他有趣的选项包括参数**-gcutil**:

$ jstat -gcutil (PID) | awk '{print($5)}'

这将以空间当前容量的百分比打印元空间利用率。

使用Java本机内存跟踪监视MetaSpace

监控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是否正在加载增量的宝贵提示

OutOfMemoryError:OpenShift/Kubernetes上的元空间

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

相关文章