- 使用命令 jps查看进程
- 使用jstat gc -1 5000查看内存占用和回收情况
正式测试 是否跑job区别。大量的job,部分用户点击的热数据 ,不同时刻在跑 600-700对比 200 多了400-500m,代码原数据(不占用堆区)占了300m,所以 堆空间=老年代(900)+700+7 约等于 1500-1600m。加上本地区(主要是栈内存(堆的对象引用指针) gc root+程序及计数器等小空间)
-server -XX:+PrintGCDetails -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Xms1600m -Xmx1600m -Xverify:none -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/log/plan01.hprof
full gc 过程: 15次=》old =>old大=》young变小=》young持续小=》young gc 频繁=>full gc
heap out of range: full gc =>old 不能变大(young 足够小)=》full gc后不能增大old的空间 容不下新来的数据。
- 使用visal vm 和mat图形化分析
排查出问题:DruidDataSource比例最高 在线程池的destroy线程中,排查可能是druid的数据源异常配置问题:
-
remove-abandoned: false=>remove-abandoned: true。
相关的其他配置 正常
time-between-eviction-runs-millis: 60000 # 1 minute
min-evictable-idle-time-millis: 300000 # 5 minutes
useGlobalDataSourceStat: false
druid配置导致堆溢出 (https://blog.****.net/lypeng13/article/details/121911981)
改动后观察启动后的 E O区的占用变化和之前趋势对比情况。和FullGc在相同时间的变化趋势
增大heap大小观察full gc -
导出dump文件的方式 1. 命令 2. 工具 3. 代码
(1)docker file 文件启动文件,堆溢出自动导出
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/log/plan01.hprof
(2)
public class FullGCHeapDump {
private static HotSpotDiagnosticMXBean hotspotMBean;
private static long lastFullGCTime = -1; // To store the time of the last Full GC
private static final long THRESHOLD = 15000; // 2 seconds in milliseconds
// Method to trigger a heap dump
public static void dumpHeap(String filePath) {
if (hotspotMBean == null) {
try {
hotspotMBean = ManagementFactory.newPlatformMXBeanProxy(
ManagementFactory.getPlatformMBeanServer(),
"com.sun.management:type=HotSpotDiagnostic",
HotSpotDiagnosticMXBean.class);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
// Dump the heap to the specified file
hotspotMBean.dumpHeap(filePath, true);
System.out.println("Heap dump created at: " + filePath);
} catch (IOException e) {
e.printStackTrace();
}
}
@PostConstruct
public void postConstruct(){
// Keep the application running so we can monitor GC events
System.out.println("Monitoring for Full GC events...");
// Register GC notification listener
for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) {
NotificationEmitter emitter = (NotificationEmitter) gcBean;
emitter.addNotificationListener(new NotificationListener() {
@Override
public void handleNotification(Notification notification, Object handback) {
String notificationType = notification.getType();
if (notificationType.equals("com.sun.management.gc.notification")) {
com.sun.management.GarbageCollectionNotificationInfo info =
com.sun.management.GarbageCollectionNotificationInfo.from((javax.management.openmbean.CompositeData) notification.getUserData());
// Check if the GC type is "end of major GC" or "Full GC"
String gcAction = info.getGcAction();
System.out.println(gcAction);
if (gcAction.contains("end of major GC") || gcAction.contains("end of Full GC")) {
System.out.println("Full GC detected.");
long currentTime = System.currentTimeMillis(); // Get the current time
if (lastFullGCTime != -1 && (currentTime - lastFullGCTime) <= THRESHOLD) {
// If two Full GCs occurred within 2 seconds, trigger the heap dump
System.out.println("Two Full GCs detected within 2 seconds. Triggering heap dump...");
FullGCHeapDump.dumpHeap("heapdump.hprof");
}
// Update the time of the last Full GC
lastFullGCTime = currentTime;
}
}
}
}, null, null);
}
}
}
5. mat实例分析查找追踪堆栈和可能得内存泄漏点
模拟堆栈溢出
@PostMapping(“post”)
public void post(){
// simulate full gc
int maxValue = Integer.MAX_VALUE;
List list = new ArrayList<>();
while (true){
for (int i = 0; i < maxValue; i++) {
list.add(new AchResult());
}
}