每次面试都会被问到JVM 、内存溢出等问题。解决方案大同小异:

1.Disabling the error check altogether, via “-XX:-UseGCOverheadLimit”. 此种方式最终会改报错为java.lang.OutOfMemoryError: Java heap space(治标不治本)

2.增大堆内存。既然堆内存少了,那就增加堆内存即可,-Xms64M -Xmx64M  ,如果存在内存泄漏,那还是治标不治本  

3.优化内存泄漏的代码(终极方案),排查思路如下:

一般生产有oom时,本地如果使用jmiter压测,适当调整堆内存都可以复现问题。以下场景为示例:

开发环境:window、idea、jdk1.8,com.github.oshi,3.9.1,

系统功能:获取服务器JVM、内存、CPU、磁盘等信息

问题现象:系统在运行3-4天时,会出现OOM的现象

java.lang.OutOfMemoryError: GC overhead limit exceeded

排查思路:

 1,使用jimiter进行现场环境模拟测试(并发数、运行时长)

OutOfMemoryError: GC Overhead Limit如何解决 Exceeded_堆内存

2,本地启动服务,双击jvisualvm.exe,使用jvisualvm监控

OutOfMemoryError: GC Overhead Limit如何解决 Exceeded_堆内存_02

OutOfMemoryError: GC Overhead Limit如何解决 Exceeded_JVM_03

通过上图可以看出内存一直在缓慢上升以及JVM 垃圾回收活动频繁。而且垃圾回收后,内存仍未减少,初步判断,程序种肯定会有的对象没有释放,导致内存无法回收。随着时间的运行,肯定会出现OOM
 

3,堆dump,分析内存种的对象

OutOfMemoryError: GC Overhead Limit如何解决 Exceeded_JVM_04

 3,如下图示例。一般情况下查看堆内存种的自己熟悉的类,即可快速定位到问题:如oshi.util.plateform.windows.PerfDataUtil

OutOfMemoryError: GC Overhead Limit如何解决 Exceeded_内存泄漏_05

 第二个方法是通过对象最多的类,看持有者是谁,点击HashMap,如下,引用对象都是指向PerfDataUtil

OutOfMemoryError: GC Overhead Limit如何解决 Exceeded_堆内存_06

找到问题,是因为调用这个对应时,这个map是被staic final修饰,所有线程都会操作这个map,如果只放不清除的话,肯定会出现OOM

OutOfMemoryError: GC Overhead Limit如何解决 Exceeded_JVM_07

修改代码,本地重新压测测试, 

private static final Map<PerfCounter, HANDLEByReference> counterMap = new HashMap<>();这个map只put 不remove.所以map会越来越大

本示例是修改版本号,将3.9.1修改成<oshi.version>6.4.1</oshi.version>

6.4.1种没有这个问题。

 修复后的效果,堆内存无明显上升趋势。测试没问题后,需要长期观察后,以防还有遗漏的情况

OutOfMemoryError: GC Overhead Limit如何解决 Exceeded_堆内存_08