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