浅谈Metaspace内存溢出原因及JVM参数设置

浅谈Metaspace内存溢出原因及JVM参数设置

1.Metaspace内存溢出(oom)

日志

在这里插入图片描述

原因分析

从Java8开始,Java中的内存模型引入了一个称为元空间(Metaspace)的新内存区域,并删除了Permgen。一般如 类的名称和字段、带有方法字节码的类的方法、常量池、访问限制等都会存在于元空间中。
metaspace空间增长大部分是由于反射类加载、动态代理生成的类加载等导致,也就是说Metaspace的大小和加载类的数据有关系,加载的类越多metaspace占用的内存也就越大那么引起Metaspace内存溢出就可以从以上几种数据源头进行分析。

常见的溢出情况:

  1. 迭代引入监控、分析类过多。比如项目上线时,经过评估设置MaxMetaspaceSize为128M,后续由于添加了各类监控、分析等功能,项目启动即接近了128M,后续自然会导致空间不足。
  2. 某个业务场景的访问量暴增,导致Metaspace内存溢出。
  3. JVM参数配置错误。这个就藏的有点深了,首先要判断反射对象是否被SoftReference软引用修饰的,如果是,则需要查看XX:SoftRefLRUPolicyMSPerMB的参数配置。SoftRefLRUPolicyMSPerMB参数大概意思是每1M空闲空间可保持的SoftReference对象的生存时长(单位是ms毫秒),JVM默认是1000ms,如果被设置为0,就会导致软引用对象马上被回收掉,进而会导致频繁的反射生成新的类,达不到复用的效果,而导致Metaspace激增。
  4. 类加载器泄漏。这个更头疼。首先要对堆转储的Dump文件进行分析,堆应该在至少一个ClassLoader实例泄漏后转储生成dump文件,这样才可以分析泄漏实例的引用,从而防止它被垃圾收集。可以添加-XX:+HeapDumpOnOutOfMemoryError JVM参数,然后运行并重新部署应用程序,直到它崩溃java.lang.OutOfMemoryError错误,崩溃前会自动生成堆转储dump文件。文件名类似于java_pid18148.hprof,.hprof文件位于应用程序服务器的启动目录中,也可以通过-XX:HeapDumpPath=/directory参数指定目录。解析.hprof文件最好使用工具吧,每个工具使用都不一样,最终通过查找引用并找到不需要的引用,可以找到导致泄漏的原因,从而防止类装入器被垃圾收集。此引用可能在业务代码、第三方库、应用程序服务器或JVM中。

解决方案

正常情况下的解决方案也很简单:

  1. 如果应用程序耗尽内存中的元空间区域,评估后重新加大元空间的配置即可。如将128M改为256M。
  2. 还可以删除MaxMetaspaceSizes配置参数,完全取消对元空间大小的限制,但这个不解决根本问题,只是临时取消了OOM的出现,留出一定的时间来检查和定位问题。
  3. 如果是-XX:SoftRefLRUPolicyMSPerMB导致的,则将其设为1000(1s)即可。

工具

  1. Arthas诊断工具(Java在线诊断利器之Arthas)
  2. 原始的 jmap和jhat
  3. MAT(内存分析器工具)

2.JVM参数设置

JVM各参数值大小的设置,根据应用程序的内存大小进行比例设置,针对个别具体的值,可微调,也可默认。

堆设置

-Xms 初始堆大小
-Xmx 最大堆大小
-Xmn 年轻代大小
-Xss 每个线程的堆栈大小
-XX:NewRatio=n 年轻代和年老代的比值。
-XX:SurvivorRatio=n 年轻代中Eden区与两个Survivor区的比值。
-XX:MaxPermSize=n 持久代大小
-XX:MaxTenuringThreshold=0 垃圾最大年龄

java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0

收集器设置

-XX:+UseSerialGC 串行收集器
-XX:+UseParallelGC 并行收集器
-XX:ParallelGCThreads 并行收集器收集时使用的CPU数。并行收集线程数
-XX:+UseParalledlOldGC 并行年老代收集器
-XX:MaxGCPauseMillis 每次年轻代垃圾回收的最长时间
-XX:+UseAdaptiveSizePolicy 并行收集器调优
-XX:+UseConcMarkSweepGC 年老代为并发收集,与-XX:NewRatio不同时设置
-XX:+UseParNewGC 年轻代为并行收集,JVM自行设置,无需配置。

-XX:+UseParallelGC -XX:ParallelGCThreads=20 -XX:+UseParallelOldGC -XX:MaxGCPauseMillis=100-XX:+UseAdaptiveSizePolicys -XX:+UseConcMarkSweepGC

垃圾回收统计信息

命令行参数,一些打印信息,调试时使用
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JVM参数设置的最佳实践可以根据具体的应用场景和需求来确定。以下是一些常见的JVM参数设置建议: 1. 内存相关参数: - -Xms:设置JVM的初始堆大小,建议与-Xmx相同,以避免堆大小动态调整带来的性能开销。 - -Xmx:设置JVM的最大堆大小,根据应用的内存需求进行适当调整。 - -Xmn:设置年轻代的大小,一般建议设置为整个堆大小的1/3到1/4。 - -XX:MaxMetaspaceSize:设置元空间(Metaspace)的最大大小,根据应用的类加载需求进行适当调整。 2. 垃圾回收相关参数: -XX:+UseG1GC:启用G1垃圾回收器,适用于大内存应用和低延迟要求。 - -XX:+UseParallelGC:启用并行垃圾回收器,适用于多核处理器和吞吐量优先的应用。 - -XX:+UseConcMarkSweepGC:启用CMS垃圾回收器,适用于低延迟要求的应用。 - -XX:ParallelGCThreads:设置并行垃圾回收的线程数,根据CPU核心数进行适当调整。 3. 线程相关参数: - -Xss:设置线程栈的大小,根据应用的线程数量和递归深度进行适当调整。 - -XX:ThreadStackSize:设置线程栈的大小,与-Xss参数功能相同,但优先级更高。 4. 其他常用参数: - -XX:+DisableExplicitGC:禁用显式垃圾回收调用,避免不必要的性能开销。 - -XX:+UseCompressedOops:启用指针压缩,减少对象引用的内存占用。 请注意,以上只是一些常见的JVM参数设置建议,具体的最佳实践还需要根据应用的具体情况进行调整和优化。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值