DEV Community

Truman
Truman

Posted on

FullGCListener


@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;
    }
}

Enter fullscreen mode Exit fullscreen mode

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;
}

Enter fullscreen mode Exit fullscreen mode

Java程序中对full GC信息的收集,在应用高峰期后,可以查看收集的GC信息,结合内存使用情况,CPU使用情况,API接口请求调用等数据综合分析,对应用进行部分或者全面的优化。

Top comments (0)