【发布时间】: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
也就是说,我想说明799M - (374M + 89M) = 316M的OffHeap内存。
每个线程消耗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 段
标签: java linux memory-leaks spring-boot jvm