如何在JVM中统计某个类所有实例的总占用大小?
获取JVM中指定类所有实例的总大小
核心现状与问题
你已经通过JVM Tool Interface(JTI)相关API拿到了目标类的所有ObjectReference实例列表:
List<ReferenceType> classes = vm.classesByName(klass.getName()); List<ObjectReference> objectReferences = classes.get(0).instances(Long.MAX_VALUE);
但这里的ObjectReference是JTI抽象的跨虚拟机对象代理引用,无法直接转换为本地JVM堆中的实际Object实例,因此不能直接传给JOL的VM.current().sizeOf()方法计算大小。
可行解决方案
方案1:通过JTI直接计算浅大小
ObjectReference本身提供了获取对象浅大小的方法,无需转换为本地对象:
long totalShallowSize = 0; for (ObjectReference objRef : objectReferences) { totalShallowSize += objRef.getSize(); }
此方法返回的是对象自身占用的内存(不包含其引用的其他对象),如果需要统计保留大小(对象被回收时可释放的总内存,包含其独有引用的对象),则需要自行实现引用链遍历与可达性分析逻辑,排除被其他对象共享引用的部分。
方案2:基于堆转储统计精确大小
如果需要更全面的保留大小统计,可通过JTI生成堆转储后离线分析:
- 生成目标JVM的堆转储文件:
File dumpFile = Files.createTempFile("heapdump", ".hprof").toFile(); vm.dumpHeap(dumpFile.getAbsolutePath(), true);
- 使用堆解析逻辑(可基于开源堆分析库或自行实现HProf格式解析)读取堆转储,统计指定类所有实例的浅大小或保留大小。
IDE实现原理参考
Eclipse和IntelliJ IDEA的内存分析功能,核心逻辑与上述方案一致:
- 浅大小直接通过JTI的
ObjectReference.getSize()获取; - 保留大小则是通过遍历对象引用图,标记仅由目标类实例引用的对象,再汇总这些对象的总大小,本质是实现了简化版的垃圾回收可达性分析。
内容的提问来源于stack exchange,提问作者NOLFXceptMe
相关产品推荐
相关产品推荐

