4年前 (2020-11-10)  jvm |   抢沙发  13845 
文章评分 1 次,平均分 5.0

这个java.lang.OutOfMemoryError:Metaspace表示为Java类元数据分配的本机内存量已被耗尽。即我们经常遇到的 java metaspace 内存溢出问题。

Java8和更高版本中,分配给Java类的最大内存量(MaxMetaspaceSize)默认是不受限制的,因此在大多数情况下不需要更改此设置。另一方面,如果您想限制Java类的内存,可以按照如下方式设置:

java -XX:MaxMetaspaceSize=3200m

问题是-XX:MaxMetaspaceSize只是一个上限。当前的元空间大小(即已提交)将更小。事实上,有一个名为MaxMetaspaceFreeRatio(默认值为70%)的设置,这意味着元空间的实际大小永远不会超过其占用率的230%。

为了让它首先增长,它必须填满,强制垃圾回收来释放对象,只有当它不能达到MinMetaspaceFreeRatio(默认值为40%)的目标时,它才会扩展当前的元空间。然而,这不能超过GC循环后入住率的230%。

Java HotSpotVM如何管理元空间数据

java hotspot按如下方式管理用于元数据的空间:从操作系统请求空间,然后将空间分成块。类装入器从其块中为元数据分配空间。

java元空间metaspace内存溢出排查方法总结

类元数据在相应的Java类被卸载并且其块被回收以供重用或返回给操作系统时释放。Java类是由于垃圾收集而卸载的,为了卸载类和释放类元数据,可能会触发垃圾收集。当为类元数据提交的空间达到某个阈值(高水位线)时,将触发垃圾回收。

垃圾收集之后,根据从类元数据中释放的空间量,可以提高或降低高水位线。如果回收后的剩余空间还是不够用就会报 metaspace outofmemory 的错误提示。

使用 jstat 命令检查元空间容量

监视元空间大小的最简单方法是使用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

下面是对标签的描述:

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

其他选项包括参数-gcutil:

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

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

从 Heap Dump 堆转储查询元空间

可以通过堆转储执行进一步的检查:

java元空间metaspace内存溢出排查方法总结

然后,如果您查看了OQL控制台,就可以执行OQL查询来对您的类执行即席分析。例如,通过执行以下查询,可以从每个类加载器加载一个类列表:

select map(sort(map(heap.objects('java.lang.ClassLoader'), '{loader: it, count: it.classes.elementCount }'), 'lhs.count < rhs.count'), 'toHtml(it) + "
"')

java元空间metaspace内存溢出排查方法总结

这是一个宝贵的提示,可以用来确定类加载器是否正在加载越来越多的类。

使用Java本机内存跟踪监视元空间大小

监视元数据确切数量的一个好方法是使用NativeMemoryTracking,可以通过以下设置添加:

-XX:+UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=detail -XX:+PrintNMTStatistics

启用本机内存跟踪后,可以使用以下命令请求JVM内存使用情况报告:

jcmd <pid> VM.native_memory

如果检查jcmd输出,您将在底部找到内部(提交)部分中提交/使用的本机内存量

本机内存跟踪:

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值是用于加载类的空间量。committed值是可用于块的空间量。保留值是为元数据保留(但不一定要提交)的空间量。

还可以使用阿里开源的Arthas在线诊断工具来排查metaspace元空间内存溢出的问题:https://javakk.com/160.html

 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/790.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册