每次面试都会被问到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进行现场环境模拟测试(并发数、运行时长)
2,本地启动服务,双击jvisualvm.exe,使用jvisualvm监控
通过上图可以看出内存一直在缓慢上升以及JVM 垃圾回收活动频繁。而且垃圾回收后,内存仍未减少,初步判断,程序种肯定会有的对象没有释放,导致内存无法回收。随着时间的运行,肯定会出现OOM
3,堆dump,分析内存种的对象
3,如下图示例。一般情况下查看堆内存种的自己熟悉的类,即可快速定位到问题:如oshi.util.plateform.windows.PerfDataUtil
第二个方法是通过对象最多的类,看持有者是谁,点击HashMap,如下,引用对象都是指向PerfDataUtil
找到问题,是因为调用这个对应时,这个map是被staic final修饰,所有线程都会操作这个map,如果只放不清除的话,肯定会出现OOM
修改代码,本地重新压测测试,
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种没有这个问题。
修复后的效果,堆内存无明显上升趋势。测试没问题后,需要长期观察后,以防还有遗漏的情况