一旦被占用的内存空间不符合释放的条件,GC没办法清理,那就会适时出现java.lang.OutOfMemoryError
。这个错误就是提醒我们这群程序猿,写GC程序的程序猿不知道这种情况怎么处理,为了安全也不便处理,谁使用Java就自己看着解决吧。
说起来,java.lang.OutOfMemoryError
有几种分类的,这次碰到的是java.lang.OutOfMemoryError: GC overhead limit exceeded
,下面就来说说这种类型的内存溢出。
简单来说,java.lang.OutOfMemoryError: GC overhead limit exceeded
发生的原因是,当前已经没有可用内存,经过多次GC之后仍然没能有效释放内存。
1. 原因
众所周知,JVM的GC过程会因为STW,只不过停顿短到不容易感知。当引起停顿时间的98%都是在进行GC,但是结果只能得到小于2%的堆内存恢复时,就会抛出java.lang.OutOfMemoryError: GC overhead limit exceeded
这个错误。Plumbr给出一个示意图:
3. 解决方法
3.1 JVM参数
JVM给出一个参数避免这个错误:-XX:-UseGCOverheadLimit
。
但是,这个参数并不是解决了内存不足的问题,只是将错误发生时间延后,并且替换成java.lang.OutOfMemoryError: Java heap space
。
3.2 堆内存
还有一个偷懒的方法是:增大堆内存。既然堆内存少了,那就增加堆内存即可。
但是,这个方法也不是万能的。因为程序里可能有内存泄露。这个时候即使再增大堆内存,也会有用完的时候。
所以前两个方法都只是治标不治本而已。
3.3 终极方法
其实还是有一个终极方法的,而且是治标治本的方法,就是找到占用内存大的地方,把代码优化了,就不会出现这个问题了。
怎么找到需要优化的代码呢?就是通过heap dump生产jvm快照,通过分析快照找到占用内存大的对象,从而找到代码位置。
通过设置-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump
参数来生产快照,然后通过VisualVM或者MAT等工具分析快照内容进行定位。通过这个参数是将发生OOM时的堆内存所有信息写入快照文件,也就是说,如果此时堆内存中有敏感信息的话,那就可能造成信息泄漏了。