java获取JVM信息

Laughing
2025-04-16 / 0 评论 / 5 阅读 / 搜一下 / 正在检测是否收录...

在Java或者Spring Boot日常开发过程中,因为Java的自动垃圾回收机制,我们可能很少关注JVM的信息,面临性能问题时,我们可能也会更多的借助JProfiler等第三方工具进行问题分析。

比如我们需要做一个程序运行健康监控功能,我们可能就需要获取Jvm的信息,下面我们就看一下如何在Java中获取Jvm信息。

首先我们定义两个公共方法,分别是用来将毫秒转换成时分秒,另外一个方法是将时间戳转换成时分秒毫秒。

/**
 * 毫秒转换成时分秒
 *
 * @param uptime 毫秒
 * @return 时分秒
 */
protected static String toDuration(double uptime) {
    NumberFormat fmtI = new DecimalFormat("###,###", new DecimalFormatSymbols(Locale.ENGLISH));
    NumberFormat fmtD = new DecimalFormat("###,##0.000", new DecimalFormatSymbols(Locale.ENGLISH));

    uptime /= 1000;
    if (uptime < 60) {
        return fmtD.format(uptime) + " 秒";
    }
    uptime /= 60;
    if (uptime < 60) {
        long minutes = (long) uptime;
        return fmtI.format(minutes) + "分";
    }
    uptime /= 60;
    if (uptime < 24) {
        long hours = (long) uptime;
        long minutes = (long)((uptime - hours) * 60);
        String s = fmtI.format(hours) + "时";
        if (minutes != 0) {
            s += " " + fmtI.format(minutes) + "分";
        }
        return s;
    }
    uptime /= 24;
    long days = (long) uptime;
    long hours = (long)((uptime - days) * 24);
    String s = fmtI.format(days) + "天";
    if (hours != 0) {
        s += " " + fmtI.format(hours) + "时";
    }
    return s;
}

/**
 * 时间戳钻日期
 *
 * @param timeStamp 时间戳
 * @return 日期
 */
protected static String timeStamp2Date(long timeStamp) {
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.ENGLISH);
    return simpleDateFormat.format(timeStamp);
}

可以获取jvm的名称、jvm版本、jvm制造商、java版本、jvm启动时间、jvm运行时间等信息

RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
System.out.printf("jvm名称:%s %n", runtimeMXBean.getVmName());
System.out.printf("jvm版本:%s %n", runtimeMXBean.getVmVersion());
System.out.printf("jvm制造商:%s %n", runtimeMXBean.getVmVendor());
System.out.printf("java版本:%s %n", System.getProperty("java.version"));
System.out.printf("jvm启动时间:%s %n", timeStamp2Date(runtimeMXBean.getStartTime()));
System.out.printf("jvm运行时间:%s %n", toDuration(runtimeMXBean.getUptime()));

m9imligp.png

可以获取编译器名称、编译耗时及是否支持及时编译器编译监控。

CompilationMXBean compilationMXBean = ManagementFactory.getCompilationMXBean();
System.out.printf("编译器名称:%s %n", compilationMXBean.getName());
System.out.printf("编译耗时:%s %n", toDuration(compilationMXBean.getTotalCompilationTime()));
System.out.printf("是否支持及时编译器编译监控:%s %n", compilationMXBean.isCompilationTimeMonitoringSupported());

m9imtw7f.png

可以获取总线程数、守护进程线程数、峰值线程数、Java虚拟机启动后创建并启动的线程总数、是否支持测量当前线程的CPU时间等信息。

ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
System.out.printf("总线程数(守护+非守护):%s %n", threadMXBean.getThreadCount());
System.out.printf("守护进程线程数:%s %n", threadMXBean.getDaemonThreadCount());
System.out.printf("峰值线程数:%s %n", threadMXBean.getPeakThreadCount());
System.out.printf("Java虚拟机启动后创建并启动的线程总数:%s %n", threadMXBean.getTotalStartedThreadCount());
System.out.printf("是否支持测量当前线程的CPU时间:%s %n", threadMXBean.isCurrentThreadCpuTimeSupported());
System.out.printf("当前线程的总CPU时间:%s %n", threadMXBean.getCurrentThreadCpuTime());
System.out.printf("当前线程在用户模式中执行的CPU时间:%s %n", threadMXBean.getCurrentThreadUserTime());

m9inc0ro.png

可以获取初始化堆内存、已使用堆内存、可使用堆内存、最大堆内存等信息

MemoryUsage heapMemoryUsage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
System.out.printf("初始化堆内存:%sm %n", heapMemoryUsage.getInit() / 1024 / 1024);
System.out.printf("已使用堆内存:%sm %n", heapMemoryUsage.getUsed() / 1024 / 1024);
System.out.printf("可使用堆内存:%sm %n", heapMemoryUsage.getCommitted() / 1024 / 1024);
System.out.printf("最大堆内存:%sm %n", heapMemoryUsage.getMax() / 1024 / 1024);

为了方便查询数据,我们可以手工编译、运行代码

javac JvmInfo.java
java -Xmx20m JvmInfo

m9io0s8d.png

也可以获取非堆内存,也就是永久代的信息。需要注意,JDK1.7之后已经废弃了永久代的概念,使用元空间进行替代

MemoryUsage noHeapMemoryUsage = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();
System.out.printf("初始化非堆内存:%sm %n", noHeapMemoryUsage.getInit() / 1024 / 1024);
System.out.printf("已使用非堆内存:%sm %n", noHeapMemoryUsage.getUsed() / 1024 / 1024);
System.out.printf("可使用非堆内存:%sm %n", noHeapMemoryUsage.getCommitted() / 1024 / 1024);
System.out.printf("最大非堆内存:%sm %n", noHeapMemoryUsage.getMax() / 1024 / 1024);

可以获取操作系统名称、操作系统版本、处理器数量、系统平均负载、电脑架构等信息

OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
System.out.printf("操作系统名称:%s %n", operatingSystemMXBean.getName());
System.out.printf("操作系统版本:%s %n", operatingSystemMXBean.getVersion());
System.out.printf("可用处理器数量%s %n", operatingSystemMXBean.getAvailableProcessors());
System.out.printf("系统平均负载:%f %n", operatingSystemMXBean.getSystemLoadAverage());
System.out.printf("电脑架构:%s %n", operatingSystemMXBean.getArch());

m9jdh5ul.png

可获取当前加载类数量、未加载类数量、总加载类数量

ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
System.out.printf("当前加载类数量%s %n", classLoadingMXBean.getLoadedClassCount());
System.out.printf("未加载类数量%s %n", classLoadingMXBean.getUnloadedClassCount());
System.out.printf("总加载类数量%s %n", classLoadingMXBean.getTotalLoadedClassCount());
 

也可以获取内存池对象

public static void main(String[] args) {
    List < MemoryPoolMXBean > memoryPoolMXBeanList = ManagementFactory.getMemoryPoolMXBeans();
    for (MemoryPoolMXBean memoryMXBean: memoryPoolMXBeanList) {
        final String kind = memoryMXBean.getType().name();
        final MemoryUsage usage = memoryMXBean.getUsage();
        System.out.println(
            "内存模型: " + getKindName(kind) + ", 内存空间名称: " + getPoolName(memoryMXBean.getName()) + ", jvm." +
            memoryMXBean.getName() + ".init(初始化):" + bytesToMB(usage.getInit()));
        System.out.println(
            "内存模型: " + getKindName(kind) + ", 内存空间名称: " + getPoolName(memoryMXBean.getName()) + ", jvm." +
            memoryMXBean.getName() + ".used(已使用): " + bytesToMB(usage.getUsed()));
        System.out.println(
            "内存模型: " + getKindName(kind) + ", 内存空间名称: " + getPoolName(memoryMXBean.getName()) + ", jvm." +
            memoryMXBean.getName() + ".committed(可使用):" + bytesToMB(usage.getCommitted()));
        System.out.println(
            "内存模型: " + getKindName(kind) + ", 内存空间名称: " + getPoolName(memoryMXBean.getName()) + ", jvm." +
            memoryMXBean.getName() + ".max(最大):" + bytesToMB(usage.getMax()));
    }
}

protected static String getKindName(String kind) {
    if ("NON_HEAP".equals(kind)) {
        return "NON_HEAP(非堆内存)";
    } else {
        return "HEAP(堆内存)";
    }
}

protected static String getPoolName(String poolName) {
    switch (poolName) {
        case "Code Cache":
            return poolName + "(代码缓存区)";
        case "Metaspace":
            return poolName + "(元空间)";
        case "Compressed Class Space":
            return poolName + "(类指针压缩空间)";
        case "PS Eden Space":
            return poolName + "(伊甸园区)";
        case "PS Survivor Space":
            return poolName + "(幸存者区)";
        case "PS Old Gen":
            return poolName + "(老年代)";
        default:
            return poolName;
    }
}

protected static String bytesToMB(long bytes) {
    return (bytes / 1024 / 1024) + " MB";
}

m9jdsjcc.png

0

评论 (0)

取消