com.github.oshi-3.9.1 java.lang.OutOfMemoryError: GC overhead limit exceeded 排查思路

每次面试都会被问到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 counterMap = new HashMap<>();这个map只put 不remove.所以map会越来越大

本示例是修改版本号,将3.9.1修改成6.4.1

6.4.1种没有这个问题。

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

 附核心代码,本项目是ruoyi老版本的问题。

package com.sany.server.monitor.domain;import com.sany.server.monitor.utils.Arith;
import com.sany.server.monitor.utils.IpUtils;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.CentralProcessor.TickType;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.software.os.FileSystem;
import oshi.software.os.OSFileStore;
import oshi.software.os.OperatingSystem;
import oshi.util.Util;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;/*** 服务器相关信息** @author devtools*/
public class Server {private static final int OSHI_WAIT_SECOND = 500;/*** CPU相关信息*/private Cpu cpu = new Cpu();/*** 內存相关信息*/private Mem mem = new Mem();/*** JVM相关信息*/private Jvm jvm = new Jvm();/*** 服务器相关信息*/private Sys sys = new Sys();private long active=0;/*** 磁盘相关信息*/private List sysFiles = new LinkedList();public Cpu getCpu() {return cpu;}public void setCpu(Cpu cpu) {this.cpu = cpu;}public Mem getMem() {return mem;}public void setMem(Mem mem) {this.mem = mem;}public Jvm getJvm() {return jvm;}public void setJvm(Jvm jvm) {this.jvm = jvm;}public Sys getSys() {return sys;}public void setSys(Sys sys) {this.sys = sys;}public long getActive() {return active;}public void setActive(long active) {this.active = active;}public List getSysFiles() {return sysFiles;}public void setSysFiles(List sysFiles) {this.sysFiles = sysFiles;}public void copyTo() throws Exception {SystemInfo si = new SystemInfo();HardwareAbstractionLayer hal = si.getHardware();setCpuInfo(hal.getProcessor());setMemInfo(hal.getMemory());setSysInfo();setJvmInfo();setSysFiles(si.getOperatingSystem());//用户活跃this.active=getUserActive();}public static long getUserActive() {try {Runtime runtime = Runtime.getRuntime();String cmds[] = {"cmd", "/c", "tasklist"};Process proc = runtime.exec(cmds);InputStream inputstream = proc.getInputStream();InputStreamReader inputstreamreader = new InputStreamReader(inputstream);BufferedReader bufferedreader = new BufferedReader(inputstreamreader);long active = bufferedreader.lines().count();bufferedreader.close();inputstream.close();proc.destroy();return active;} catch (Exception e) {e.printStackTrace();}return 0;}/*** 设置CPU信息*/private void setCpuInfo(CentralProcessor processor) {// CPU信息long[] prevTicks = processor.getSystemCpuLoadTicks();Util.sleep(OSHI_WAIT_SECOND);long[] ticks = processor.getSystemCpuLoadTicks();long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;cpu.setCpuNum(processor.getLogicalProcessorCount());cpu.setTotal(totalCpu);cpu.setSys(cSys);cpu.setUsed(user);cpu.setWait(iowait);cpu.setFree(idle);}/*** 设置内存信息*/private void setMemInfo(GlobalMemory memory) {mem.setTotal(memory.getTotal());mem.setUsed(memory.getTotal() - memory.getAvailable());mem.setFree(memory.getAvailable());}/*** 设置服务器信息*/private void setSysInfo() {Properties props = System.getProperties();sys.setComputerName(IpUtils.getHostName());sys.setComputerIp(IpUtils.getHostIp());sys.setOsName(props.getProperty("os.name"));sys.setOsArch(props.getProperty("os.arch"));sys.setUserDir(props.getProperty("user.dir"));}/*** 设置Java虚拟机*/private void setJvmInfo() throws UnknownHostException {Properties props = System.getProperties();jvm.setTotal(Runtime.getRuntime().totalMemory());jvm.setMax(Runtime.getRuntime().maxMemory());jvm.setFree(Runtime.getRuntime().freeMemory());jvm.setVersion(props.getProperty("java.version"));jvm.setHome(props.getProperty("java.home"));}/*** 设置磁盘信息*/private void setSysFiles(OperatingSystem os) {FileSystem fileSystem = os.getFileSystem();OSFileStore[] fsArray = fileSystem.getFileStores();for (OSFileStore fs : fsArray) {long free = fs.getUsableSpace();long total = fs.getTotalSpace();long used = total - free;SysFile sysFile = new SysFile();sysFile.setDirName(fs.getMount());sysFile.setSysTypeName(fs.getType());sysFile.setTypeName(fs.getName());sysFile.setTotal(convertFileSize(total));sysFile.setFree(convertFileSize(free));sysFile.setUsed(convertFileSize(used));sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100));sysFiles.add(sysFile);}}/*** 字节转换** @param size 字节大小* @return 转换后值*/public String convertFileSize(long size) {long kb = 1024;long mb = kb * 1024;long gb = mb * 1024;if (size >= gb) {return String.format("%.1f GB", (float) size / gb);} else if (size >= mb) {float f = (float) size / mb;return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);} else if (size >= kb) {float f = (float) size / kb;return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);} else {return String.format("%d B", size);}}
}


4.0.0com.sany.server.monitorserver-monitor1.1.0jarmonitor服务器状态监控org.springframework.bootspring-boot-starter-parent2.1.1.RELEASEUTF-8UTF-81.83.9.1com.github.oshioshi-core${oshi.version}org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-thymeleaf${project.artifactId}org.springframework.bootspring-boot-maven-plugintrue publicaliyun nexushttp://maven.aliyun.com/nexus/content/groups/public/truepublicaliyun nexushttp://maven.aliyun.com/nexus/content/groups/public/truefalse


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部