MemoryPoolMXBean.getUsage() 返回轻量、近似、非绝对精确的内存使用快照,含init/used/committed/max四字段;max可能为-1,此时不可用于水位计算,需改用绝对阈值或peakUsage。

MemoryPoolMXBean.getUsage() 返回的是当前内存池的实时使用快照,但它不是“绝对精确”的瞬时值,而是一个轻量、近似、可快速获取的内存使用视图。
这个快照包含四个关键字段(单位:字节):
-
getInit():初始分配大小(通常由 JVM 启动参数决定,如-Xms对应堆区) -
getUsed():当前已使用的内存量(重点关注) -
getCommitted():JVM 当前已向操作系统申请并保证可用的内存(即“已提交”部分) -
getMax():该内存池理论上最大可用容量(注意:可能为-1,表示无固定上限)
⚠️ 关键注意事项
-
不是所有池都支持
getMax()有效值
比如 G1 的"G1 Survivor Space"、Metaspace、CodeCache 等池,getMax()常返回-1。此时不能用used / max计算水位,应改用:- 绝对阈值(如
getUsed() > 256MB) - 或回退到
getPeakUsage().getMax()(仅作参考,因 peak 不实时更新)
- 绝对阈值(如
getUsage()是轻量操作,但某些场景下开销较大
例如对象未连续分配(如 Survivor 区碎片化严重)时,JVM 可能需遍历结构才能估算used,文档要求实现方明确说明是否昂贵。它不触发 GC,也不阻塞应用线程
所以适合高频轮询(如每秒一次),但别指望它反映“下一毫秒”的突变。快照是调用时刻的静态副本
多次调用getUsage()得到的是不同时间点的独立对象,内部字段不可变(MemoryUsage是不可变类)。
✅ 正确用法示例
for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
MemoryUsage usage = pool.getUsage();
long used = usage.getUsed();
long max = usage.getMax();
if (max > 0) {
double usageRatio = (double) used / max;
System.out.printf("%s: %.2f%% (%d/%d MB)%n",
pool.getName(),
usageRatio * 100,
used / 1024 / 1024,
max / 1024 / 1024);
} else {
System.out.printf("%s: %d MB (max unknown)%n",
pool.getName(), used / 1024 / 1024);
}
}
❌ 常见误用
- 把
getUsage()当作“内存泄漏检测唯一依据”——它只告诉你用了多少,不解释为什么没释放 - 直接对
getMax() == -1的池做除法,导致NaN或告警失灵 - 在循环中反复调用
ManagementFactory.getPlatformMXBean(MemoryPoolMXBean.class)—— 这会抛异常,必须用getMemoryPoolMXBeans()获取列表
不复杂但容易忽略










