性能问答>JVM到底占用了多少内存>
2回复

JVM到底占用了多少内存



各位大佬请见谅,请教一个问题新手问题:按照JVM的内存区域来划分,内存区域划分为:方法区,本地方法栈,虚拟机栈,堆,程序计数器。想知道程序就只有这几块会用内存嘛?堆的大小可以很好的统计到,也是很常用的设置。

问题一:请问有什么办法或者是资料可以让我学习到如何统计其他几块内存区域所占用的内存呢。
top查看进程占用内存:

jinfo 1 显示如下:


问题二:很想知道 出了堆以外,其他地区(本地方法栈,虚拟机栈)会占用到其他这么多内存嘛?

948 阅读
请先登录,再评论

如果想要了解HotSpot的内存使用情况可以去使用Oracle官方的工具NMT(Native Memory Tracking)(出门左转https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html)。
开启NMT之后使用jcmd查看summary data,会打印以下数据(示例):
Total: reserved=1421497KB, committed=40349KB
- Java Heap (reserved=102400KB, committed=20480KB)
(mmap: reserved=102400KB, committed=20480KB)

- Class (reserved=1056893KB, committed=4989KB)
(classes #427)
(malloc=125KB #130)
(mmap: reserved=1056768KB, committed=4864KB)

- Thread (reserved=10304KB, committed=10304KB)
(thread #11)
(stack: reserved=10260KB, committed=10260KB)
(malloc=33KB #52)
(arena=12KB #18)

- Code (reserved=249630KB, committed=2566KB)
(malloc=30KB #302)
(mmap: reserved=249600KB, committed=2536KB)

- GC (reserved=347KB, committed=87KB)
(malloc=7KB #79)
(mmap: reserved=340KB, committed=80KB)

- Compiler (reserved=132KB, committed=132KB)
(malloc=1KB #22)
(arena=131KB #5)

- Internal (reserved=211KB, committed=211KB)
(malloc=179KB #1267)
(mmap: reserved=32KB, committed=32KB)

- Symbol (reserved=1374KB, committed=1374KB)
(malloc=918KB #94)
(arena=456KB #1)

- Native Memory Tracking (reserved=34KB, committed=34KB)
(malloc=2KB #29)
(tracking overhead=31KB)

- Arena Chunk (reserved=171KB, committed=171KB)
(malloc=171KB)

其中reserved和committed好理解,reserved就是预留出来的总的虚拟内存(这个值与TOP命令统计的VIRT并不完全相同,VIRT包含一些NMT统计不到的内存,所以可以理解为VIRT的子集,这个后面再解释),commited就是实际提交使用的内存(也可以简单理解为真实使用的物理内存大小,这个大小一般是和TOP统计出的RES相对应的),举个最简单的例子:如果使用 -Xms100m -Xmx1000m 运行,Hotspot将为 Java 堆保留 1000 MB,由于初始堆大小只有 100 MB,因此开始时只会提交 100 MB(当然你也可以通过 -XX:+AlwaysPreTouch 之类参数强制分配物理内存来抵消内存延迟分配)。

继续往下看,Java Heap就不用说了,即Java堆的大小。Class就是类的meta data元数据,这部分在JVM规范中属于方法区,具体到Hotspot的JDK8之后属于Metaspace。Thread就是各种线程与线程堆栈。Code就是JIT编译器存放编译后存放的机器码。Compiler 就是JIT编译器线程在编译code时本身所使用的内存。GC 就是垃圾收集器时使用的数据,例如卡表Card Table。Internal就是不适合前面几类的内存,比如命令行解析器使用的内存,JVMTI等等。 Symbol就是Hotspot使用的符号表(StringTable、ConstantPool等)。而Native Memory Tracking就NMT自身所用到的内存。至于最后的 Unknown则是下面几种情况:1)当内存类别无法确定时;2)虚拟内存:当类型信息尚未到达时。

这大致就是Hotspot在OS中的内存布局了,但是前面为什么说reserved和VIRT不完全相同呢?因为NMT虽然可以追踪到heap、code、threads、Unsafe.allocateMemory 和 DirectByteBuffer 等等申请的内存,但是却不包含 JNI 调用的的第三方Native Code申请的内存和JDK class libraries。所以VIRT一般是会比reserved大的,但如果大很多,那就很有可能是 glibc malloc 管理的内存出了问题(比如著名的64M问题)(Hotspot一般通过mmap或者glibc malloc来分配各区域内存)。

可以简单的用下面这张图来对应:
132ba6ba720f2bfc6c69b1ce490f7c87693987.jpg

不过我们观察也可以看出,Hotspot内存占用的大头无非就是heap、threads、Metaspace、code cache、native memory。

55月前
回复 豆大侠:

谢谢,真诚感谢。很受益!👍👍

5月前回复