1. 概述

本文将介绍如何使用 纯 JDK 提供的核心 API 来监控 Java 应用的关键运行指标,主要包括:

  • ✅ 磁盘空间使用情况
  • ✅ JVM 内存使用
  • ✅ 线程与 CPU 时间消耗

我们不会引入任何第三方库,所有示例均基于 JDK 自带的 java.io.Filejava.lang.management.ManagementFactory 类实现。

最后还会简单提一下如何用 Java Profiler 做更全面的监控,避免自己重复造轮子。


2. File 类简介

File 类是对文件或目录路径的抽象,不仅能操作文件,还能获取文件系统信息,并保证跨平台路径兼容性(比如 Windows 用 \,Linux 用 /)。

本文中,我们将用它来获取系统磁盘的总空间、可用空间等信息,适用于 Windows 和 Linux 环境。


3. ManagementFactory 简介

ManagementFactory 是 JDK 提供的一个工厂类,用于获取 JVM 的各种 管理 Bean(MXBean),这些 Bean 暴露了 JVM 内部的运行时数据。

我们重点关注以下两个:

3.1 MemoryMXBean

代表 JVM 内存系统的管理接口。JVM 启动后会自动创建一个实例,通过 ManagementFactory.getMemoryMXBean() 可获取。

可用于监控堆内存的使用、初始大小、最大限制等。

3.2 ThreadMXBean

代表 JVM 线程系统的管理接口,通过 ManagementFactory.getThreadMXBean() 获取。

它可以获取当前所有线程的 ThreadInfo 对象,进而分析线程状态、CPU 占用时间等,对排查死锁、线程阻塞等问题非常有用。


4. 监控磁盘使用情况

使用 File 类可以轻松获取指定磁盘分区的空间信息。下面以 Windows 的 C 盘为例:

File cDrive = new File("C:");
System.out.println(String.format("Total space: %.2f GB",
  (double)cDrive.getTotalSpace() / 1073741824));
System.out.println(String.format("Free space: %.2f GB", 
  (double)cDrive.getFreeSpace() / 1073741824));
System.out.println(String.format("Usable space: %.2f GB", 
  (double)cDrive.getUsableSpace() / 1073741824));

✅ 输出示例:

Total space: 476.94 GB
Free space: 210.32 GB
Usable space: 210.32 GB

⚠️ 注意:

  • getTotalSpace():磁盘总容量
  • getFreeSpace():未被占用的空间
  • getUsableSpace():当前用户可使用的空间(可能受权限或保留空间影响)

在 Linux 上只需换成根目录 / 即可:

File root = new File("/");
System.out.println(String.format("Total space: %.2f GB", 
  (double)root.getTotalSpace() / 1073741824));
System.out.println(String.format("Free space: %.2f GB", 
  (double)root.getFreeSpace() / 1073741824));
System.out.println(String.format("Usable space: %.2f GB", 
  (double)root.getUsableSpace() / 1073741824));

📌 小贴士:返回值单位是字节,我们除以 1073741824(即 1024³)转为 GB,提升可读性。


5. 监控 JVM 内存使用

通过 MemoryMXBean 可以实时获取 JVM 堆内存的使用情况:

MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
System.out.println(String.format("Initial memory: %.2f GB", 
  (double)memoryMXBean.getHeapMemoryUsage().getInit() / 1073741824));
System.out.println(String.format("Used heap memory: %.2f GB", 
  (double)memoryMXBean.getHeapMemoryUsage().getUsed() / 1073741824));
System.out.println(String.format("Max heap memory: %.2f GB", 
  (double)memoryMXBean.getHeapMemoryUsage().getMax() / 1073741824));
System.out.println(String.format("Committed memory: %.2f GB", 
  (double)memoryMXBean.getHeapMemoryUsage().getCommitted() / 1073741824));

✅ 输出示例:

Initial memory: 0.25 GB
Used heap memory: 0.08 GB
Max heap memory: 4.00 GB
Committed memory: 0.50 GB

📌 各字段含义:

字段 说明
init JVM 启动时申请的初始堆内存
used 当前已使用的堆内存
max 堆内存最大值,超过会抛 OutOfMemoryError
committed JVM 向操作系统保证可用的内存(已提交)

⚠️ 注意:max-Xmx 参数限制,若未设置,默认为系统内存的 1/4 左右。


6. 监控线程与 CPU 使用

ThreadMXBean 能获取所有线程的运行时信息,包括状态、CPU 时间等,适合做性能分析或排查线程泄漏。

ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();

for (Long threadID : threadMXBean.getAllThreadIds()) {
    ThreadInfo info = threadMXBean.getThreadInfo(threadID);
    System.out.println("Thread name: " + info.getThreadName());
    System.out.println("Thread State: " + info.getThreadState());
    System.out.println(String.format("CPU time: %s ns", 
      threadMXBean.getThreadCpuTime(threadID)));
}

✅ 输出示例:

Thread name: main
Thread State: RUNNABLE
CPU time: 123456789 ns

📌 关键点:

  • getAllThreadIds():获取当前所有线程 ID
  • getThreadInfo(threadId):获取线程详细信息
  • getThreadCpuTime(threadId):返回线程使用的 CPU 时间(纳秒),仅当 CPU 时间监控开启时有效(默认开启)

💡 实际应用中,可定期采样 CPU 时间差值,计算线程的 CPU 占用率。


7. 使用 Profiler 监控指标(推荐方式)

上面的方法虽然简单,但属于“手动打点”,适合轻量级监控或嵌入到日志中。

但如果你需要更全面、实时的分析,强烈建议使用 Java Profiler,它们能无侵入地监控:

  • ✅ 内存分配与 GC 行为
  • ✅ 线程阻塞、死锁检测
  • ✅ 方法调用耗时(CPU Profiling)
  • ✅ 类加载、JVM 参数等

常见工具:

  • VisualVM:JDK 自带(Java 6 起),免费、轻量,支持本地/远程监控
  • JConsole:同样 JDK 自带,功能较基础
  • JProfilerYourKit:商业工具,功能强大,适合生产问题排查
  • Async-Profiler:开源高性能采样器,支持火焰图生成

📌 开发阶段建议在 IDE 中安装 VisualVM 插件,简单粗暴地看内存和线程状态,比写代码查 ManagementFactory 快多了。


8. 总结

本文介绍了如何使用 JDK 原生 API 监控 Java 应用的关键指标:

  • File 类:快速获取磁盘空间(跨平台)
  • MemoryMXBean:查看 JVM 堆内存使用
  • ThreadMXBean:分析线程状态与 CPU 时间
  • ✅ Profiler:生产环境推荐方案,无需编码即可全面监控

💡 踩坑提醒:

  • getUsableSpace() 在某些文件系统上可能和 getFreeSpace() 不一致(如保留空间)
  • getThreadCpuTime() 返回 null?检查是否启用了 CPU 时间监控
  • max 内存可能小于物理内存,受 -Xmx 限制

对于线上服务,建议结合 Micrometer + Prometheus 做长期指标采集,而本文方法更适合临时排查或嵌入健康检查接口。


原始标题:Monitoring Disk Usage and Other Metrics in Java