JVM 进程如何分配其内存?
Posted
技术标签:
【中文标题】JVM 进程如何分配其内存?【英文标题】:How does a JVM process allocate its memory? 【发布时间】:2016-05-31 20:26:23 【问题描述】:我在理解 JVM 进程如何分配自己的内存方面存在一些差距。据我所知
RSS = Heap size + MetaSpace + OffHeap size
其中 OffHeap 由线程堆栈、直接缓冲区、映射文件(库和 jar)和 JVM 代码本身组成;
目前我正在尝试分析我的 Java 应用程序(Spring Boot + Infinispan),其 RSS 为 779M(它在 docker 容器中运行,因此 pid 1 可以):
[ root@daf5a5ae9bb7:/data ]$ ps -o rss,vsz,sz 1
RSS VSZ SZ
798324 6242160 1560540
根据jvisualvm
,committed Heap size是374M
元空间大小为 89M
也就是说,我想说明799M - (374M + 89M) = 316M的OffHeap内存。
我的应用有(平均)36 个活动线程。
每个线程消耗1M:
[ root@fac6d0dfbbb4:/data ]$ java -XX:+PrintFlagsFinal -version |grep ThreadStackSize
intx CompilerThreadStackSize = 0
intx ThreadStackSize = 1024
intx VMThreadStackSize = 1024
所以,我们可以在这里添加 36M。
应用使用 DirectBuffer 的唯一地方是 NIO。据我从 JMX 可以看出,它并没有消耗很多资源——只有 98K
最后一步是映射库和罐子。但是根据pmap
(full output)
[ root@daf5a5ae9bb7:/data ]$ pmap -x 1 | grep ".so.*" | awk ' sum+=$3 END print sum'
12896K
加
root@daf5a5ae9bb7:/data ]$ pmap -x 1 | grep “.jar" | awk ' sum+=$3 END print sum'
9720K
我们这里只有 20M。
因此,我们还是要解释一下316M - (36M + 20M) = 260M :(
有人知道我错过了什么吗?
【问题讨论】:
JVM本身的所有共享库都有。尝试运行两个 JVM,看看增加了多少。 为出色的研究+1! 100% 同意@PeterLawrey。通过执行ldd /path/to/java' and 'pmap PID
来检查 Java 正在运行哪些共享库,以详细了解 Java 到底使用了什么。
另外,正如你所看到的,“used”比实际的堆大小要小得多。 VM 喜欢占用大量内存来提高 GC 性能。即使是使用过的堆,也有很多可能是死对象,在执行完整 GC 时会被回收。
+ CodeCache(用于动态生成的代码)+ GC 内部结构(如 CardTables)+ 本地库分配的结构(I/O、网络等)+ JVM 和库的 .bss 段
【参考方案1】:
方法:
您可能想使用Java HotSpot Native Memory Tracking (NMT)。
这可能会为您提供 JVM 分配的内存的准确列表,分为不同的区域 堆、类、线程、代码、GC、编译器、内部、符号、内存跟踪、池化空闲块、 和 未知。
用法:
您可以使用-XX:NativeMemoryTracking=summary
启动您的应用程序。
可以使用jcmd <pid> VM.native_memory summary
观察当前堆。
在哪里可以找到 jcmd/pid:
在 Ubuntu 上的默认 OpedJDK 安装中,可以在 /usr/bin/jcmd
找到。
通过不带任何参数运行jcmd
,您可以获得正在运行的Java 应用程序的列表。
user@pc:~$ /usr/bin/jcmd
5169 Main <-- 5169 is the pid
输出:
然后,您将收到堆的完整概览,如下所示:
总计: reserved=664192KB,committed=253120KB
Java 堆(保留=516096KB,提交=204800KB)
(mmap:保留=516096KB,提交=204800KB)
类(保留=6568KB,提交=4140KB)
(classes #665)
(malloc=424KB, #1000)
(mmap:保留=6144KB,提交=3716KB)
线程(保留=6868KB,提交=6868KB) (线程 #15)
(stack: reserved=6780KB, committed=6780KB)
(malloc=27KB, #66)
(arena=61KB, #30)
代码(保留=102414KB,提交=6314KB)
(malloc=2574KB, #74316)
(mmap:保留=99840KB,提交=3740KB)
GC(保留=26154KB,提交=24938KB)
(malloc=486KB, #110)
(mmap:保留=25668KB,提交=24452KB)
编译器(保留=106KB,提交=106KB)
(malloc=7KB, #90)
(竞技场=99KB,#3)
内部(保留=586KB,提交=554KB)
(malloc=554KB, #1677)
(mmap:保留=32KB,提交=0KB)
符号(保留=906KB,提交=906KB)
(malloc=514KB, #2736)
(竞技场=392KB,#1)
内存跟踪(保留=3184KB,提交=3184KB)
(malloc=3184KB, #300)
池化的空闲块(保留=1276KB,提交=1276KB)
(malloc=1276KB)
未知(保留=33KB,提交=33KB)
(竞技场=33KB,#1)
这给出了 JVM 使用的不同内存区域的详细概述,并且还显示了 reserved 和 commited 内存。
我不知道有什么技术可以为您提供更详细的内存消耗列表。
进一步阅读:
您还可以将-XX:NativeMemoryTracking=detail
与更多jcmd
命令结合使用。更详细的解释可以在Java Platform, Standard Edition Troubleshooting Guide - 2.6 The jcmd Utility 找到。您可以通过"jcmd <pid> help"
查看可能的命令
【讨论】:
您在jcmp
中有错字?
谢谢,稍后会解决这个问题。
感谢您的回答!我尝试使用 NMT 并发现它非常有帮助......但我仍然有一个问题 :) NMT 说我丢失的所有内存都属于“Unkonwn”部分。当我尝试分析详细信息时,我发现以下内容:gist.github.com/krestjaninoff/a89ee990d94d8fc2917a您对这段记忆发生了什么有任何想法?它被 CMS 消耗了吗?
“此版本中的 NMT 不跟踪第三方本机代码内存分配和 JDK 类库。” (c) 好的,问题结束了:)
以上是关于JVM 进程如何分配其内存?的主要内容,如果未能解决你的问题,请参考以下文章