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

标签 linux memory jvm hadoop-yarn

当运行启用了 native 内存跟踪的 Java 应用程序(在 YARN 中)时(-XX:NativeMemoryTracking=detail 参见 https://docs.oracle.com/javase/8/docs/technotes/guides/vm/nmt-8.htmlhttps://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html),我可以看到 JVM 在不同类别中使用了多少内存。

我在 jdk 1.8.0_45 上的应用显示:

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) 

这显示了 2.7GB 的已提交内存,包括 1.3GB 的已分配堆和几乎 1.2GB 的已分配线程堆栈(使用许多线程)。

但是,在运行 ps ax -o pid,rss | grep <mypid> 时或 top它仅显示 1.6GB 的 RES/rss常驻内存。检查交换说没有使用中:

free -m
             total       used       free     shared    buffers     cached
Mem:        129180      99348      29831          0       2689      73024
-/+ buffers/cache:      23633     105546
Swap:        15624          0      15624

为什么只驻留 1.6GB 内存时 JVM 指示已提交 2.7GB 内存?剩下的都去哪儿了?

最佳答案

I'm beginning to suspect that stack memory (unlike the JVM heap) seems to be precommitted without becoming resident and over time becomes resident only up to the high water mark of actual stack usage.

是的,除非另有说明,否则至少在 linux mmap 上是惰性的。匿名页面仅在写入后才由物理内存支持(由于 zero-page optimization 导致读取不足)

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

如需进一步确认,您可以使用 pmap -x <java pid>并将各种地址范围的 RSS 与 NMT 的虚拟内存映射的输出进行交叉引用。


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

拥有可供将来使用的连续地址范围很重要,这反过来又简化了指针运算。

Committed-but-not-backed-by-storage 内存已映射 - 例如 - PROT_READ | PROT_WRITE但访问它仍然会导致页面错误。但是该页面错误由内核静默处理,方法是使用实​​际内存支持它并返回执行,就好像什么都没发生一样。
即这是流程本身不会注意到的实现细节/优化。


对概念进行分解:

Used Heap:事件对象根据上次GC占用的内存量

已提交:已使用除 PROT_NONE 以外的其他内容映射的地址范围。由于延迟分配和分页,它们可能有也可能没有物理或交换支持。

保留:已通过 mmap 预先映射的总地址范围对于特定的内存池。
保留 - 已提交 差异包括 PROT_NONE映射,保证不受物理内存支持

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

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

关于linux - 为什么 JVM 报告的已提交内存比 linux 进程驻留集大小更多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31173374/

相关文章:

python - 将数据通过管道传输到 python 调试器并交互式编写 python 程序

c - #include-ing 在 Ubuntu 上的旧 C 源代码(page.h 等)中的某些头文件

java - 我的java程序可以使用磁盘作为大对象的堆吗?

java - 监控和分析 java 中的类加载器

java - 将 JVM/JRE 设置为自动使用 Windows 代理

jvm - 如何在当前机器上运行jvm

jquery - 将远程脚本的 http 请求重定向到本地计算机 (Linux) 上的脚本

c - scanf 从函数到数组

c# - 我的内存在哪里?重新初始化数据表

windows - XML 编辑/查看软件