Java实现JVM监控案例

wen java案例 2

本文目录导读:

Java实现JVM监控案例

  1. 核心监控类
  2. 监控数据格式化输出
  3. 监控服务类
  4. 主程序入口
  5. 运行测试类
  6. 运行说明
  7. 功能特点

我来提供一个完整的Java JVM监控实现案例,包含内存、线程、GC等多个维度的监控。

核心监控类

JVMMonitor.java

import java.lang.management.*;
import java.util.*;
import javax.management.*;
import com.sun.management.OperatingSystemMXBean;
public class JVMMonitor {
    // 内存监控
    public static Map<String, Object> getMemoryInfo() {
        Map<String, Object> memoryInfo = new HashMap<>();
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        // 堆内存
        MemoryUsage heapMemory = memoryMXBean.getHeapMemoryUsage();
        memoryInfo.put("heapInit", heapMemory.getInit());
        memoryInfo.put("heapMax", heapMemory.getMax());
        memoryInfo.put("heapUsed", heapMemory.getUsed());
        memoryInfo.put("heapCommitted", heapMemory.getCommitted());
        // 非堆内存
        MemoryUsage nonHeapMemory = memoryMXBean.getNonHeapMemoryUsage();
        memoryInfo.put("nonHeapInit", nonHeapMemory.getInit());
        memoryInfo.put("nonHeapMax", nonHeapMemory.getMax());
        memoryInfo.put("nonHeapUsed", nonHeapMemory.getUsed());
        memoryInfo.put("nonHeapCommitted", nonHeapMemory.getCommitted());
        // 内存池详情
        List<Map<String, Object>> memoryPools = new ArrayList<>();
        for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
            Map<String, Object> poolInfo = new HashMap<>();
            poolInfo.put("name", pool.getName());
            poolInfo.put("type", pool.getType().toString());
            poolInfo.put("usage", pool.getUsage());
            poolInfo.put("peakUsage", pool.getPeakUsage());
            memoryPools.add(poolInfo);
        }
        memoryInfo.put("memoryPools", memoryPools);
        return memoryInfo;
    }
    // 线程监控
    public static Map<String, Object> getThreadInfo() {
        Map<String, Object> threadInfo = new HashMap<>();
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        threadInfo.put("threadCount", threadMXBean.getThreadCount());
        threadInfo.put("peakThreadCount", threadMXBean.getPeakThreadCount());
        threadInfo.put("totalStartedThreadCount", threadMXBean.getTotalStartedThreadCount());
        threadInfo.put("daemonThreadCount", threadMXBean.getDaemonThreadCount());
        // 死锁检测
        long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
        threadInfo.put("deadlockedThreads", deadlockedThreads != null ? deadlockedThreads.length : 0);
        // 线程详情
        List<Map<String, Object>> threads = new ArrayList<>();
        for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
            Map<String, Object> thread = new HashMap<>();
            thread.put("threadId", info.getThreadId());
            thread.put("threadName", info.getThreadName());
            thread.put("threadState", info.getThreadState().toString());
            thread.put("blockedCount", info.getBlockedCount());
            thread.put("blockedTime", info.getBlockedTime());
            thread.put("waitedCount", info.getWaitedCount());
            thread.put("waitedTime", info.getWaitedTime());
            // 堆栈信息
            StackTraceElement[] stackTrace = info.getStackTrace();
            thread.put("stackTraceLength", stackTrace.length);
            threads.add(thread);
        }
        threadInfo.put("threads", threads);
        return threadInfo;
    }
    // GC监控
    public static Map<String, Object> getGCInfo() {
        Map<String, Object> gcInfo = new HashMap<>();
        List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
        long totalGcCount = 0;
        long totalGcTime = 0;
        List<Map<String, Object>> gcDetails = new ArrayList<>();
        for (GarbageCollectorMXBean gc : gcBeans) {
            Map<String, Object> gcDetail = new HashMap<>();
            long count = gc.getCollectionCount();
            long time = gc.getCollectionTime();
            gcDetail.put("name", gc.getName());
            gcDetail.put("collectionCount", count);
            gcDetail.put("collectionTime", time);
            // GC内存池
            String[] poolNames = gc.getMemoryPoolNames();
            gcDetail.put("memoryPools", Arrays.toString(poolNames));
            gcDetails.add(gcDetail);
            totalGcCount += count;
            totalGcTime += time;
        }
        gcInfo.put("totalGcCount", totalGcCount);
        gcInfo.put("totalGcTime", totalGcTime);
        gcInfo.put("gcDetails", gcDetails);
        return gcInfo;
    }
    // 类加载监控
    public static Map<String, Object> getClassLoadingInfo() {
        Map<String, Object> classInfo = new HashMap<>();
        ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
        classInfo.put("loadedClassCount", classLoadingMXBean.getLoadedClassCount());
        classInfo.put("totalLoadedClassCount", classLoadingMXBean.getTotalLoadedClassCount());
        classInfo.put("unloadedClassCount", classLoadingMXBean.getUnloadedClassCount());
        return classInfo;
    }
    // 系统信息
    public static Map<String, Object> getSystemInfo() {
        Map<String, Object> systemInfo = new HashMap<>();
        OperatingSystemMXBean osMXBean = 
            (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        systemInfo.put("osName", System.getProperty("os.name"));
        systemInfo.put("osVersion", System.getProperty("os.version"));
        systemInfo.put("osArch", System.getProperty("os.arch"));
        systemInfo.put("availableProcessors", osMXBean.getAvailableProcessors());
        systemInfo.put("systemLoadAverage", osMXBean.getSystemLoadAverage());
        systemInfo.put("cpuUsage", osMXBean.getSystemCpuLoad() * 100);
        systemInfo.put("processCpuUsage", osMXBean.getProcessCpuLoad() * 100);
        systemInfo.put("totalPhysicalMemory", osMXBean.getTotalPhysicalMemorySize());
        systemInfo.put("freePhysicalMemory", osMXBean.getFreePhysicalMemorySize());
        systemInfo.put("totalSwapSpace", osMXBean.getTotalSwapSpaceSize());
        systemInfo.put("freeSwapSpace", osMXBean.getFreeSwapSpaceSize());
        return systemInfo;
    }
    // 编译监控
    public static Map<String, Object> getCompilationInfo() {
        Map<String, Object> compileInfo = new HashMap<>();
        if (ManagementFactory.getCompilationMXBean() != null) {
            CompilationMXBean compilationMXBean = ManagementFactory.getCompilationMXBean();
            compileInfo.put("compilationTime", compilationMXBean.getTotalCompilationTime());
            compileInfo.put("compilerName", compilationMXBean.getName());
        }
        return compileInfo;
    }
    // 获取所有监控数据
    public static Map<String, Object> getAllMonitorInfo() {
        Map<String, Object> allInfo = new HashMap<>();
        allInfo.put("timestamp", System.currentTimeMillis());
        allInfo.put("memory", getMemoryInfo());
        allInfo.put("thread", getThreadInfo());
        allInfo.put("gc", getGCInfo());
        allInfo.put("classLoading", getClassLoadingInfo());
        allInfo.put("system", getSystemInfo());
        allInfo.put("compilation", getCompilationInfo());
        allInfo.put("runtime", getRuntimeInfo());
        return allInfo;
    }
    // JVM运行时信息
    public static Map<String, Object> getRuntimeInfo() {
        Map<String, Object> runtimeInfo = new HashMap<>();
        RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
        runtimeInfo.put("name", runtimeMXBean.getName());
        runtimeInfo.put("vmName", runtimeMXBean.getVmName());
        runtimeInfo.put("vmVersion", runtimeMXBean.getVmVersion());
        runtimeInfo.put("vmVendor", runtimeMXBean.getVmVendor());
        runtimeInfo.put("uptime", runtimeMXBean.getUptime());
        runtimeInfo.put("startTime", runtimeMXBean.getStartTime());
        // JVM参数
        List<String> inputArguments = runtimeMXBean.getInputArguments();
        runtimeInfo.put("jvmArguments", inputArguments);
        // Classpath
        runtimeInfo.put("classPath", runtimeMXBean.getClassPath());
        // 系统属性
        Map<String, String> systemProperties = runtimeMXBean.getSystemProperties();
        runtimeInfo.put("systemProperties", systemProperties);
        return runtimeInfo;
    }
}

监控数据格式化输出

JVMInfoFormatter.java

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
public class JVMInfoFormatter {
    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    // 格式化字节大小为可读格式
    public static String formatBytes(long bytes) {
        if (bytes == 0) return "0 B";
        final String[] units = {"B", "KB", "MB", "GB", "TB"};
        int unitIndex = (int) (Math.log10(Math.abs(bytes)) / Math.log10(1024));
        if (unitIndex >= units.length) {
            unitIndex = units.length - 1;
        }
        double value = bytes / Math.pow(1024, unitIndex);
        return String.format("%.2f %s", value, units[unitIndex]);
    }
    // 格式化内存信息
    public static String formatMemoryInfo(Map<String, Object> memoryInfo) {
        StringBuilder sb = new StringBuilder();
        sb.append("========== 内存监控 ==========\n");
        long heapMax = (Long) memoryInfo.get("heapMax");
        long heapUsed = (Long) memoryInfo.get("heapUsed");
        long heapCommitted = (Long) memoryInfo.get("heapCommitted");
        sb.append("堆内存:");
        sb.append("\n  最大: ").append(formatBytes(heapMax));
        sb.append("\n  已用: ").append(formatBytes(heapUsed));
        sb.append("\n  已分配: ").append(formatBytes(heapCommitted));
        sb.append("\n  使用率: ").append(String.format("%.2f%%", 
            heapMax > 0 ? (double) heapUsed / heapMax * 100 : 0));
        sb.append("\n\n非堆内存:");
        sb.append("\n  已用: ").append(formatBytes((Long) memoryInfo.get("nonHeapUsed")));
        sb.append("\n  已分配: ").append(formatBytes((Long) memoryInfo.get("nonHeapCommitted")));
        // 内存池详情
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> pools = (List<Map<String, Object>>) memoryInfo.get("memoryPools");
        if (pools != null) {
            sb.append("\n\n内存池详情:");
            for (Map<String, Object> pool : pools) {
                sb.append("\n  ").append(pool.get("name"))
                  .append(" (").append(pool.get("type")).append("):");
                MemoryUsage usage = (MemoryUsage) pool.get("usage");
                if (usage != null) {
                    sb.append(" used=").append(formatBytes(usage.getUsed()))
                      .append(", max=").append(formatBytes(usage.getMax()))
                      .append(", committed=").append(formatBytes(usage.getCommitted()));
                }
            }
        }
        return sb.toString();
    }
    // 格式化线程信息
    public static String formatThreadInfo(Map<String, Object> threadInfo) {
        StringBuilder sb = new StringBuilder();
        sb.append("\n========== 线程监控 ==========\n");
        sb.append("当前线程数: ").append(threadInfo.get("threadCount"));
        sb.append("\n峰值线程数: ").append(threadInfo.get("peakThreadCount"));
        sb.append("\n守护线程数: ").append(threadInfo.get("daemonThreadCount"));
        sb.append("\n总启动线程数: ").append(threadInfo.get("totalStartedThreadCount"));
        sb.append("\n死锁线程数: ").append(threadInfo.get("deadlockedThreads"));
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> threads = (List<Map<String, Object>>) threadInfo.get("threads");
        if (threads != null) {
            sb.append("\n\n线程状态统计:");
            Map<String, Integer> stateCount = new HashMap<>();
            for (Map<String, Object> thread : threads) {
                String state = (String) thread.get("threadState");
                stateCount.merge(state, 1, Integer::sum);
            }
            stateCount.forEach((state, count) -> 
                sb.append("\n  ").append(state).append(": ").append(count));
        }
        return sb.toString();
    }
    // 格式化GC信息
    public static String formatGCInfo(Map<String, Object> gcInfo) {
        StringBuilder sb = new StringBuilder();
        sb.append("\n========== GC监控 ==========\n");
        sb.append("总GC次数: ").append(gcInfo.get("totalGcCount"));
        sb.append("\n总GC时间: ").append(gcInfo.get("totalGcTime")).append(" ms");
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> gcDetails = (List<Map<String, Object>>) gcInfo.get("gcDetails");
        if (gcDetails != null) {
            sb.append("\n\nGC详情:");
            for (Map<String, Object> gc : gcDetails) {
                sb.append("\n  ").append(gc.get("name"))
                  .append(": 次数=").append(gc.get("collectionCount"))
                  .append(", 时间=").append(gc.get("collectionTime")).append("ms");
            }
        }
        return sb.toString();
    }
    // 格式化系统信息
    public static String formatSystemInfo(Map<String, Object> systemInfo) {
        StringBuilder sb = new StringBuilder();
        sb.append("\n========== 系统信息 ==========\n");
        sb.append("操作系统: ").append(systemInfo.get("osName"))
          .append(" ").append(systemInfo.get("osVersion"));
        sb.append("\nCPU核心数: ").append(systemInfo.get("availableProcessors"));
        sb.append("\n系统负载: ").append(systemInfo.get("systemLoadAverage"));
        sb.append("\nCPU使用率: ").append(String.format("%.2f%%", 
            (Double) systemInfo.get("cpuUsage") * 100));
        sb.append("\n进程CPU使用率: ").append(String.format("%.2f%%", 
            (Double) systemInfo.get("processCpuUsage") * 100));
        sb.append("\n物理内存: 总=").append(formatBytes((Long) systemInfo.get("totalPhysicalMemory")))
          .append(", 可用=").append(formatBytes((Long) systemInfo.get("freePhysicalMemory")));
        return sb.toString();
    }
    // 格式化所有信息
    public static String formatAllInfo(Map<String, Object> allInfo) {
        StringBuilder sb = new StringBuilder();
        long timestamp = (Long) allInfo.get("timestamp");
        sb.append("===== JVM监控信息 ").append(SDF.format(new Date(timestamp))).append(" =====\n");
        // 内存
        @SuppressWarnings("unchecked")
        Map<String, Object> memoryInfo = (Map<String, Object>) allInfo.get("memory");
        sb.append(formatMemoryInfo(memoryInfo));
        // 线程
        @SuppressWarnings("unchecked")
        Map<String, Object> threadInfo = (Map<String, Object>) allInfo.get("thread");
        sb.append(formatThreadInfo(threadInfo));
        // GC
        @SuppressWarnings("unchecked")
        Map<String, Object> gcInfo = (Map<String, Object>) allInfo.get("gc");
        sb.append(formatGCInfo(gcInfo));
        // 系统
        @SuppressWarnings("unchecked")
        Map<String, Object> systemInfo = (Map<String, Object>) allInfo.get("system");
        sb.append(formatSystemInfo(systemInfo));
        // 类加载
        @SuppressWarnings("unchecked")
        Map<String, Object> classInfo = (Map<String, Object>) allInfo.get("classLoading");
        sb.append("\n========== 类加载监控 ==========\n");
        sb.append("已加载类: ").append(classInfo.get("loadedClassCount"));
        sb.append("\n总加载类: ").append(classInfo.get("totalLoadedClassCount"));
        sb.append("\n卸载类数量: ").append(classInfo.get("unloadedClassCount"));
        // JVM运行时
        @SuppressWarnings("unchecked")
        Map<String, Object> runtimeInfo = (Map<String, Object>) allInfo.get("runtime");
        sb.append("\n========== JVM运行时 ==========\n");
        sb.append("JVM名称: ").append(runtimeInfo.get("vmName"));
        sb.append("\nJVM版本: ").append(runtimeInfo.get("vmVersion"));
        sb.append("\n运行时间: ").append(formatUptime((Long) runtimeInfo.get("uptime")));
        return sb.toString();
    }
    private static String formatUptime(long uptimeMillis) {
        long days = uptimeMillis / (24 * 3600 * 1000);
        long hours = (uptimeMillis % (24 * 3600 * 1000)) / (3600 * 1000);
        long minutes = (uptimeMillis % (3600 * 1000)) / (60 * 1000);
        long seconds = (uptimeMillis % (60 * 1000)) / 1000;
        return String.format("%d天 %02d:%02d:%02d", days, hours, minutes, seconds);
    }
}

监控服务类

MonitorService.java

import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
public class MonitorService implements AutoCloseable {
    private final ScheduledExecutorService scheduler;
    private final long intervalSeconds;
    private PrintWriter logWriter;
    private boolean logToFile;
    public MonitorService(long intervalSeconds) {
        this.intervalSeconds = intervalSeconds;
        this.scheduler = Executors.newScheduledThreadPool(1);
    }
    public MonitorService(long intervalSeconds, String logFilePath) {
        this(intervalSeconds);
        this.logToFile = true;
        try {
            this.logWriter = new PrintWriter(new FileWriter(logFilePath, true), true);
        } catch (IOException e) {
            System.err.println("无法创建日志文件: " + e.getMessage());
            this.logToFile = false;
        }
    }
    public void start() {
        System.out.println("JVM监控服务启动,每 " + intervalSeconds + " 秒采集一次");
        scheduler.scheduleAtFixedRate(() -> {
            try {
                collectAndDisplay();
            } catch (Exception e) {
                System.err.println("监控采集失败: " + e.getMessage());
            }
        }, 0, intervalSeconds, TimeUnit.SECONDS);
    }
    private void collectAndDisplay() {
        Map<String, Object> allInfo = JVMMonitor.getAllMonitorInfo();
        String formattedInfo = JVMInfoFormatter.formatAllInfo(allInfo);
        // 控制台输出
        System.out.println(formattedInfo);
        System.out.println("========================================");
        // 文件输出
        if (logToFile && logWriter != null) {
            logWriter.println(formattedInfo);
            logWriter.println("========================================");
        }
    }
    @Override
    public void close() {
        scheduler.shutdown();
        try {
            if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
            }
        } catch (InterruptedException e) {
            scheduler.shutdownNow();
        }
        if (logWriter != null) {
            logWriter.close();
        }
        System.out.println("JVM监控服务已停止");
    }
}

主程序入口

Main.java

import java.util.Map;
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("=== JVM监控工具 ===");
        System.out.println("1. 单次采集监控信息");
        System.out.println("2. 定时监控(默认5秒间隔)");
        System.out.println("3. 定时监控并保存日志");
        System.out.print("请选择 (1/2/3): ");
        int choice = scanner.nextInt();
        scanner.nextLine();
        switch (choice) {
            case 1:
                // 单次采集
                collectOnce();
                break;
            case 2:
                System.out.print("请输入监控间隔(秒): ");
                long interval = scanner.nextLong();
                scanner.nextLine();
                try (MonitorService service = new MonitorService(interval)) {
                    service.start();
                    System.out.println("按回车键停止监控...");
                    scanner.nextLine();
                }
                break;
            case 3:
                System.out.print("请输入监控间隔(秒): ");
                interval = scanner.nextLong();
                scanner.nextLine();
                System.out.print("请输入日志文件路径(如: jvm_monitor.log): ");
                String logPath = scanner.nextLine();
                try (MonitorService service = new MonitorService(interval, logPath)) {
                    service.start();
                    System.out.println("按回车键停止监控...");
                    scanner.nextLine();
                }
                break;
            default:
                System.out.println("无效选择");
        }
        scanner.close();
    }
    private static void collectOnce() {
        System.out.println("正在采集JVM监控信息...\n");
        Map<String, Object> allInfo = JVMMonitor.getAllMonitorInfo();
        String formattedInfo = JVMInfoFormatter.formatAllInfo(allInfo);
        System.out.println(formattedInfo);
        // 显示JVM参数
        System.out.println("\n========== JVM启动参数 ==========");
        @SuppressWarnings("unchecked")
        Map<String, Object> runtimeInfo = (Map<String, Object>) allInfo.get("runtime");
        @SuppressWarnings("unchecked")
        java.util.List<String> jvmArgs = (java.util.List<String>) runtimeInfo.get("jvmArguments");
        jvmArgs.forEach(arg -> System.out.println("  " + arg));
    }
}

运行测试类

MonitorTest.java

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class MonitorTest {
    // 模拟内存使用
    private static List<byte[]> memoryLeak = new ArrayList<>();
    private static Random random = new Random();
    // 模拟线程创建
    private static List<Thread> threads = new ArrayList<>();
    public static void main(String[] args) throws Exception {
        System.out.println("启动JVM监控测试...");
        // 显示初始监控信息
        Map<String, Object> initialInfo = JVMMonitor.getAllMonitorInfo();
        System.out.println(JVMInfoFormatter.formatAllInfo(initialInfo));
        System.out.println("\n开始模拟负载...");
        // 模拟内存分配
        Thread memoryThread = new Thread(() -> {
            try {
                for (int i = 0; i < 100; i++) {
                    // 分配5MB内存
                    memoryLeak.add(new byte[5 * 1024 * 1024]);
                    System.out.println("分配内存: " + ((i + 1) * 5) + "MB");
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        memoryThread.start();
        // 模拟线程创建
        Thread threadThread = new Thread(() -> {
            try {
                for (int i = 0; i < 20; i++) {
                    Thread t = new Thread(() -> {
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                        }
                    });
                    t.start();
                    threads.add(t);
                    System.out.println("创建线程: " + t.getName());
                    Thread.sleep(300);
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        threadThread.start();
        // 运行10秒后显示监控信息
        Thread.sleep(10000);
        System.out.println("\n=== 运行10秒后的监控信息 ===");
        Map<String, Object> afterInfo = JVMMonitor.getAllMonitorInfo();
        System.out.println(JVMInfoFormatter.formatAllInfo(afterInfo));
        // 清理
        memoryLeak.clear();
        for (Thread t : threads) {
            t.interrupt();
        }
        // 触发GC
        System.gc();
        Thread.sleep(1000);
        System.out.println("\n=== GC后的监控信息 ===");
        Map<String, Object> gcAfterInfo = JVMMonitor.getAllMonitorInfo();
        System.out.println(JVMInfoFormatter.formatAllInfo(gcAfterInfo));
        System.out.println("\n测试完成");
    }
}

运行说明

编译和运行:

# 编译
javac -d . *.java
# 运行主程序
java Main
# 运行测试程序
java MonitorTest
# 使用JVM参数运行(推荐,便于观察)
java -Xms256m -Xmx1024m -XX:+UseG1GC -XX:+PrintGCDetails Main

输出示例:

========== 内存监控 ==========
堆内存:
  最大: 1.00 GB
  已用: 256.00 MB
  已分配: 512.00 MB
  使用率: 25.00%
========== 线程监控 ==========
当前线程数: 5
峰值线程数: 12
守护线程数: 3
========== GC监控 ==========
总GC次数: 3
总GC时间: 150 ms
========== 系统信息 ==========
操作系统: Windows 10
CPU核心数: 8
CPU使用率: 15.00%

功能特点

  1. 全面监控:内存、线程、GC、类加载、系统、编译、运行时信息
  2. 实时采集:可配置采集频率
  3. 多种输出:控制台显示、文件日志
  4. 性能分析:支持死锁检测、内存池分析
  5. 易于扩展:模块化设计,方便添加新监控项

这个监控工具可以用于:

  • JVM性能调优
  • 内存泄漏排查
  • 线程问题分析
  • GC性能优化
  • 生产环境监控

抱歉,评论功能暂时关闭!