@Slf4j
@Configuration
public class FullGCListener implements InitializingBean {
private final static String G1 = "G1";
private final static String ParallelGC = "ParallelGC";
private final static String CMS = "CMS";
private final static String ZGC = "ZGC";
private final static String ShenandoahGC = "ShenandoahGC";
private final static String SerialGC = "SerialGC";
private final static String UNKNOWN = "unknown";
@Override
public void afterPropertiesSet() throws Exception {
// 获取所有垃圾收集器的 MXBeans
List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean gcBean : gcBeans) {
// 为每个垃圾收集器 MXBean 添加监听器
NotificationEmitter emitter = (NotificationEmitter) gcBean;
emitter.addNotificationListener(new NotificationListener() {
@Override
public void handleNotification(Notification notification, Object handback) {
if (notification.getType().equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) {
GarbageCollectionNotificationInfo info = GarbageCollectionNotificationInfo.from((CompositeData) notification.getUserData());
String gcType = info.getGcAction();
if ("end of major GC".equals(gcType)
|| "end of full GC".equals(gcType)
|| "end of minor GC".equals(gcType)) {
String beforeString = "before Full GC " + VMUtil.getCodeCacheUsageString();
String gcMessage = MessageFormat.format(
"Full GC occurred: - GC ID: {0} - GC Cause: {1} - GC Duration: {2} ms",
info.getGcInfo().getId(),
info.getGcCause(),
info.getGcInfo().getDuration()
);
String afterString = "after Full GC " + VMUtil.getCodeCacheUsageString();
String content = "Time:"+ LDTUtils.nowString() + "\n"
+ beforeString + "\n"
+ gcMessage + "\n"
+ afterString + "\n"
+ "------------------------------------\n";
File file = new File("GCListenerLog.txt");
try {
FileUtils.writeStringToFile(file, content, "UTF-8", true);
} catch (IOException e) {
}
}
}
}
}, null, null);
}
}
private static String getGCAlgorithm(String gcName) {
String gcAlgorithm = UNKNOWN;
if (gcName.contains("G1")) {
gcAlgorithm = G1;
} else if (gcName.contains("PS Scavenge") || gcName.contains("PS MarkSweep")) {
gcAlgorithm = ParallelGC;
} else if (gcName.contains("ConcurrentMarkSweep")) {
gcAlgorithm = CMS;
} else if (gcName.contains("ZGC")) {
gcAlgorithm = ZGC;
} else if (gcName.contains("Shenandoah")) {
gcAlgorithm = ShenandoahGC;
} else if (gcName.contains("Serial") || gcName.contains("Copy") || gcName.contains("MarkSweepCompact")) {
gcAlgorithm = SerialGC;
} else {
log.info("无法确定的GC算法: " + gcName);
}
return gcAlgorithm;
}
}
getCodeCacheUsageString method
public static String getCodeCacheUsageString() {
String codeCacheMessage = null;
List<MemoryPoolMXBean> memoryPoolMXBeans = ManagementFactory.getMemoryPoolMXBeans();
// Iterate over all memory pools to find the Code Cache
for (MemoryPoolMXBean memoryPoolMXBean : memoryPoolMXBeans) {
String name = memoryPoolMXBean.getName();
// Check for specific memory pools in Java 21 or Java 1.8
boolean isAnalyze21 = StrUtil.startWith(javaVersion, "21")
&& (StrUtil.equals("CodeHeap 'non-nmethods'", name)
|| StrUtil.equals("CodeHeap 'profiled nmethods'", name));
boolean isAnalyze8 = StrUtil.startWith(javaVersion, "1.8") && StrUtil.equals("Code Cache", name);
if (isAnalyze21 || isAnalyze8) {
// Format and return the code cache memory usage details
codeCacheMessage = MessageFormat.format(
"Java version: {0}, {1} Code Cache Usage:\n - Initial: {2} bytes\n - Used: {3} bytes\n" +
" - Committed: {4} bytes\n - Max: {5} bytes",
javaVersion,
name,
memoryPoolMXBean.getUsage().getInit(),
memoryPoolMXBean.getUsage().getUsed(),
memoryPoolMXBean.getUsage().getCommitted(),
memoryPoolMXBean.getUsage().getMax()
);
return codeCacheMessage;
}
}
return codeCacheMessage;
}
Java程序中对full GC信息的收集,在应用高峰期后,可以查看收集的GC信息,结合内存使用情况,CPU使用情况,API接口请求调用等数据综合分析,对应用进行部分或者全面的优化。
Top comments (0)