【发布时间】:2020-01-29 10:26:47
【问题描述】:
使用jdk1.8.0_152我正在尝试追踪我的java程序的哪一部分使用的内存最多(主要在堆中)
使用top我看到整个过程使用了大约1.109G的剩余内存
使用jcmd {PID} VM.native_memory 我看到保留的总大小为 4704896 KB,提交的大小约为 1290820 KB。
已提交的内存略多于剩余内存,但我读过并非所有已提交的内存都可以分页到实际内存,所以我不太担心这种差异
我现在主要关心的是VM.native_memory 的堆内存使用量与我使用jcmd {PID} GC.class_histogram 时的总堆内存使用量之间的差异
我还尝试使用jstat -gc {PID} 比较堆使用情况,得到的结果类似于GC.class_histogram
根据GC.class_histogram 和jstat -gc,堆使用量约为250MB,但使用VM.native_memory 堆使用量(在Java Heap 部分中提交)约为1000000KB(小于1GB)但实际的RSS 内存似乎更接近VM.native_memory中的承诺总数
我现在的猜测是 VM.native_memory Java Heap 包含尚未被垃圾回收的内存,但即使我运行垃圾回收,我看到 jstat -gc 的结果急剧下降,而 VM.native_memory 根本不受影响(虽然我听说用户手动调用垃圾收集并不总是会导致完整的垃圾收集,但至少 jstat -gc 似乎与 GC.class_histogram 的结果相匹配。
我听说的另一件事是top 的剩余内存在使用内存的进程释放它时并不总是被释放,直到绝对需要释放该内存。
总结一下
- 为什么
VM.native_memory显示的堆内存使用量与jstat和GC.class_histogram不同? - 我应该使用哪个指标来确定我的 java 进程正在使用多少内存? (鉴于
top中的剩余内存可能并不总是反映实际使用情况)
【问题讨论】:
-
@Holger 根据docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/… 本地内存似乎是指 Java Hotspot VM 使用的所有内存,包括堆以及其他内存,例如线程(堆栈)、类缓存等
-
我明白了,所以你不明白“提交”并不意味着“用 Java 对象填充”意义上的“使用”?
-
@Holger 嗯.. 是的,如果我理解正确的话?但根据文档,它说“请注意,实际上只使用了提交的内存。”所以看起来应该“使用”已提交。根据总承诺与
top所说的进程正在使用的相似程度,看起来应该“使用”已提交? (虽然剩余内存可能是指 jvm 已锁定的总内存与实际“充满对象”的内存相比。但根据文档,“提交”似乎是指实际填充该内存的对象“) -
尚未提交的内存,显然没有被使用。但是,已经使用但由于垃圾回收而变得空闲的堆内存仍然被提交,并将被重用于后续分配。将内存回馈给系统的情况很少发生,一些垃圾收集器永远不会回馈。
-
已提交的 RAM 不一定是上限,必要时可能会尝试提交更多内容(不过,通常在尝试提交更多内容之前至少会尝试一次垃圾收集)。另请参阅this summary。
标签: java memory garbage-collection jstat jcmd