深入JVM虚拟机之JVM可能会发生哪几种OOM?如何进行排查和处理?

总览:

1、当JVM内存严重不足时,会抛出java.lang.OutOfMemoryError:xxxx错误

2、根据实际生产经验,OOM是非常严重的问题,一般会对程序日志中的OutOfMemeoryError配置关键字告警,一经发现,立即处理。

Java Heap Space :

当堆内存没有足够的空间存放创建的对象时,就会抛出java.lang.OutOfMemoryError:Java heap space错误:

1、请求创建一个巨大对象,通常是一个大数组

2、超出预期的访问量、数据量、比如流动飙升的促销、秒杀活动

3、内存泄露(Memory Leak)的出现,大量对象引用没有释放,JVM无法对其自动回收,比如ThreadLocal、线程池无界队列等

针对大部分情况,通常只需要通过 -Xmx参数调高JVM堆内存空间即可。如果仍然没有解决,可以参考以下情况做进一步处理:

1、如果是超大对象,可以检查其合理性,比如是否一次性查询了数据库全部结果,而没有做结果数限制

2、如果是业务峰值压力,可以考虑添加机器资源,或者做限流降级

GC overhead limit exceeded

1、话费超过98%的时间来做GC,但回收不到2%的堆内存,且该动作连续重复了5次,就会抛出java.lang.OutMemoryError:GC overhead limit exceed错误

2、简单地说,就是应用程序已经基本耗尽了所有可用内存,GC也无法回收

3、JVM给出这样一个参数: -XX:UserGCOverheadLimit 禁用这个检查,其实这个参数解决不了内存问题,只是把错误的信息延后,替换成javalang.OutMememoryError:Java heap space

Permgen space 

该错误表示永久代(Permanent Generation)已用满,通常是因为加载的class数目太多或体积太大

解决方案:

1、程序启动报错,修改 -XX:MaxPermSize 启动参数,调大永久代空间

2、应用程序部署时报错,很可能应用程序没有重启,导致加载了多封class信息,只需要重启JVM即可解决。

3、运行时报错,应用程序可能会动态创建大量class,而这些class的生命周期和短暂,但是JVM默认不会卸载class,可以设置 -XX:+CMSClassUnloadingEnabled和-XX:+UserMarkSweepGC这两个参数允许JVM 卸载class

4、如果上述方法无法解决,可以通过  jmap  命令dump内存对象,逐一分析开销最大的classloader和重复class

Metaspace

JDK8后使用元空间(Metaspace)替换了永久代(Permanent Generation),该错误表示Metaspace已被用满,通常还是因为加载的class数目太多或体积太大

Unable to creat new native thread 

Java 线程(用户线程)对应着操作系统的内核级线程

Java 线程的创建会通过JVM向底层操作系统请求创建一个新的native线程,如果没有足够的资源分配就会报此类错误

解决方案:

1、升级配置,为机器提供更多的内存

2、修复应用程序的线程泄露问题

3、限制线程池大小

4、使用 -Xss参数减少线程栈的大小

Direct buffer memory

堆外内存一旦使用超过限制,就会抛出Direct buffer memoey错误

解决方案:

1、检查是否直接或间接使用了NIO,如netty,jetty等

2、通过启动参数 -XX:MaxDirectMemporySize调整Direct ByteBuffer的上限值

3、检查JVM的参数值是否有 -XX:+DisableExolicitGC选项,如果有就去掉,因为该参数会使System.gc()失效

总结:

1、OOM错误是非常严重的错误,线上出现时需要第一时间处理

2、需要大量经验来判断,尽可能对出现的场景做好总结

          

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章