如何无探查器获取JVM累计分配总内存?及代码正确性验证
你的代码分析与修正建议
咱们先直接说结论:你这段代码不能实现你想要的“当前节点已分配总内存”的需求,结果会有明显误导性,核心问题出在getPeakUsage()方法的使用上。
问题根源
getPeakUsage()返回的是对应内存池自JVM启动(或最后调用resetPeakUsage()重置峰值以来)达到过的最大内存使用量,而不是当前时刻的内存状态。举个例子:如果你的程序之前有过一次内存占用高峰,之后内存已经被释放了,这段代码算出来的还是那个高峰值,完全反映不了当前节点的真实已分配内存。
修正后的代码
要获取当前时刻的已分配总内存,你需要把getPeakUsage()替换为getUsage(),这才是内存池的当前实时内存使用情况。修改后的代码如下:
ManagementFactory.getMemoryPoolMXBeans() .stream() .map(MemoryPoolMXBean::getUsage) .filter(usage -> usage != null) .mapToLong(MemoryUsage::getUsed) .sum();
额外的细节说明
- 区分
getUsed()和getCommitted():getUsed()是当前已经被Java对象占用的内存量(真正“已分配使用”的部分)getCommitted()是JVM已经从操作系统申请到的总内存量(包含已使用和未被使用但已分配给JVM的部分)
如果你要的是“JVM从系统拿到的所有已分配内存”,那把mapToLong(MemoryUsage::getUsed)改成mapToLong(MemoryUsage::getCommitted)即可。
- 你代码里的
filter(usage -> usage != null)很有必要,因为某些平台下的特定内存池可能会返回null的内存使用数据,这个过滤能避免空指针异常。 - 如果只需要堆内存的整体情况,也可以用更简洁的方式:
ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(),它直接返回整个堆的内存状态,不用遍历所有内存池,但遍历内存池能让你了解新生代、老年代等各个区域的详细内存使用。
内容的提问来源于stack exchange,提问作者Sina Madani
相关产品推荐
相关产品推荐

