为什么JVM报告的提交内存比linux进程驻留集大小更多?

为什么JVM报告的提交内存比linux进程驻留集大小更多?,linux,memory,jvm,yarn,Linux,Memory,Jvm,Yarn,当运行一个启用了本机内存跟踪的Java应用程序(在纱线中)(-XX:NativeMemoryTracking=detail请参见和)时,我可以看到JVM在不同类别中使用了多少内存 我在jdk 1.8.045上的应用程序显示: Native Memory Tracking: Total: reserved=4023326KB, committed=2762382KB - Java Heap (reserved=1331200KB, committed=133120

当运行一个启用了本机内存跟踪的Java应用程序(在纱线中)(
-XX:NativeMemoryTracking=detail
请参见和)时,我可以看到JVM在不同类别中使用了多少内存

我在jdk 1.8.045上的应用程序显示:

Native Memory Tracking: Total: reserved=4023326KB, committed=2762382KB - Java Heap (reserved=1331200KB, committed=1331200KB) (mmap: reserved=1331200KB, committed=1331200KB) - Class (reserved=1108143KB, committed=64559KB) (classes #8621) (malloc=6319KB #17371) (mmap: reserved=1101824KB, committed=58240KB) - Thread (reserved=1190668KB, committed=1190668KB) (thread #1154) (stack: reserved=1185284KB, committed=1185284KB) (malloc=3809KB #5771) (arena=1575KB #2306) - Code (reserved=255744KB, committed=38384KB) (malloc=6144KB #8858) (mmap: reserved=249600KB, committed=32240KB) - GC (reserved=54995KB, committed=54995KB) (malloc=5775KB #217) (mmap: reserved=49220KB, committed=49220KB) - Compiler (reserved=267KB, committed=267KB) (malloc=137KB #333) (arena=131KB #3) - Internal (reserved=65106KB, committed=65106KB) (malloc=65074KB #29652) (mmap: reserved=32KB, committed=32KB) - Symbol (reserved=13622KB, committed=13622KB) (malloc=12016KB #128199) (arena=1606KB #1) - Native Memory Tracking (reserved=3361KB, committed=3361KB) (malloc=287KB #3994) (tracking overhead=3075KB) - Arena Chunk (reserved=220KB, committed=220KB) (malloc=220KB) 当只有1.6GB内存驻留时,为什么JVM指示提交了2.7GB内存?其余的去了哪里

我开始怀疑堆栈内存(与JVM堆不同)似乎是在没有驻留的情况下预提交的,并且随着时间的推移,只有在达到实际堆栈使用的最高水位时才会驻留

是的,至少在linux上mmap是懒惰的,除非另有说明。匿名页只有在写入后才由物理内存支持(由于

复制收集器或预调零(
-XX:+AlwaysPreTouch
)会有效地触及GC堆内存,因此它将始终驻留。线程堆栈otoh不受此影响

为了进一步确认,您可以使用
pmap-x
并将不同地址范围的RSS与NMT虚拟内存映射的输出进行交叉引用


保留内存已与
PROT\u NONE
混合。这意味着虚拟地址空间范围在内核的vma结构中有条目,因此不会被其他mmap/malloc调用使用。但它们仍然会导致页面错误作为SIGSEGV转发到进程,即访问它们是一个错误

重要的是要有连续的地址范围供将来使用,这反过来又简化了指针算法

已提交但未由存储内存支持的已映射(例如,
PROT_READ | PROT_WRITE
),但访问它仍会导致页面错误。但是这个页面错误是由内核通过使用实际内存对其进行支持并返回到执行状态(就好像什么都没发生一样)来静默处理的。
也就是说,这是流程本身不会注意到的实施细节/优化


要对概念进行细分,请执行以下操作:

已用堆:根据上一次GC,活动对象占用的内存量

Committed:已映射为非PROT_NONE的地址范围。由于延迟分配和分页,它们可能由物理或交换支持,也可能不由物理或交换支持

Reserved:通过
mmap
为特定内存池预先映射的总地址范围。
保留的− 提交的差异由
PROT_NONE
映射组成,这些映射保证不受物理内存的支持

Resident:当前在物理ram中的页面。这意味着代码、堆栈、提交内存池的一部分,以及最近被访问的mmaped文件的一部分,以及JVM无法控制的分配


Virtual:所有虚拟地址映射的总和。包括已提交的保留内存池,但也包括映射文件或共享内存。这个数字很少提供信息,因为JVM可以提前保留非常大的地址范围或mmap大文件。

可能重复的数字。这个问题和答案讨论保留但未提交的内存,并指出提交和驻留的内存之间的区别,我指出的不是这里的情况。答案也涵盖了承诺和常驻之间的区别。它包括一句话“已经被调出(或从未被调进)的东西可以是承诺的记忆,但不是常驻的”,这远远不足以帮助我理解我的情况,例如。这是我明确指出的一个原因,然而,在这里被传呼并不是一个充分的解释。我开始怀疑堆栈内存(与JVM堆不同)似乎是在没有驻留的情况下预提交的,并且随着时间的推移,只有在达到实际堆栈使用的最高水位时才会驻留。对此的确认或解释将是一个有用的答案。通过pmap-x确认,NMT detail Typical给出的螺纹范围的RSS在1028个左右的螺纹中仅为88个。谢谢你的提示。你能解释一下committed的实际含义吗?如果它们都可以引用尚未实际驻留/使用的虚拟内存,那么committed与reserved有何区别?谢谢!非常有用。如果JVM本机内存跟踪实际检查了pmap-x所做的数据并显示了实际驻留的数据,那就太棒了。您好,从保留到提交的转换需要将vma的prot标志从
prot_NONE
更改为
prot_WRITE
prot_READ
。然而,我没有发现任何系统调用可以做这样的事情。您能帮我解释一下吗?@JichaoZhang
mmap
带有
MAP\u FIXED
标志可以用来更新现有的映射。谢谢您这么快的回复。那么sys call mprotect:呢?似乎MProtect也可以改变vma的保护。 free -m total used free shared buffers cached Mem: 129180 99348 29831 0 2689 73024 -/+ buffers/cache: 23633 105546 Swap: 15624 0 15624