Java 本机内存跟踪堆提交的数量远远超过堆转储的总数
Posted
技术标签:
【中文标题】Java 本机内存跟踪堆提交的数量远远超过堆转储的总数【英文标题】:Java native memory tracking heap committed much more than total from heap dump 【发布时间】: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。
【参考方案1】:
我猜你的 jvm 堆已经设置了一个范围大小。
本机内存跟踪器从 os 视图显示内存大小(接近于top
命令),而jstat
从 jvm 内部视图显示。
这意味着jvm会向os请求mem(检查来自top
),但真正使用与否取决于它自己(检查jstat
或jmap
)。
【讨论】:
以上是关于Java 本机内存跟踪堆提交的数量远远超过堆转储的总数的主要内容,如果未能解决你的问题,请参考以下文章