JVM进程如何分配内存?

mik*_*ail 12 java linux jvm memory-leaks spring-boot

我在理解JVM进程如何分配自己的内存方面有一点差距.我所知道的

RSS = Heap size + MetaSpace + OffHeap size
Run Code Online (Sandbox Code Playgroud)

其中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
Run Code Online (Sandbox Code Playgroud)

据称jvisualvm,承诺堆大小为374M 在此输入图像描述

Metasapce大小为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
Run Code Online (Sandbox Code Playgroud)

所以,在这里我们可以添加36M.

应用程序使用DirectBuffer的唯一地方是NIO.据我所知,从JMX可以看出,它不会消耗大量资源 - 只有98K 在此输入图像描述

最后一步是映射libs和jar.但根据pmap(完整输出)

[ root@daf5a5ae9bb7:/data ]$ pmap -x 1 | grep ".so.*" | awk '{ sum+=$3} END {print sum}'

12896K
Run Code Online (Sandbox Code Playgroud)

加

root@daf5a5ae9bb7:/data ]$ pmap -x 1 | grep “.jar" | awk '{ sum+=$3} END {print sum}'

9720K
Run Code Online (Sandbox Code Playgroud)

我们这里只有20M.

因此,我们仍然需要解释316M - (36M + 20M)= 260M :(

有谁知道我错过了什么?

Mar*_*ger 8

做法:

您可能希望使用Java HotSpot本机内存跟踪(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
Run Code Online (Sandbox Code Playgroud)

输出:

然后,您将收到有关堆的完整概述,如下所示:

总计: 保留= 664192KB,已提交= 253120KB <---本机内存跟踪跟踪的总内存

  • Java堆(保留= 516096KB,已提交= 204800KB)<--- Java堆

    (mmap:保留= 516096KB,已提交= 204800KB)

  • 类(保留= 6568KB,已提交= 4140KB)<---类元数据

    (类#665)<---加载类的数量

    (malloc = 424KB,#1000)<--- malloc'd memory,#malloc的数量

    (mmap:保留= 6144KB,已提交= 3716KB)

  • 线程(保留= 6868KB,已提交= 6868KB)(线程#15)<---线程数

    (stack:reserved = 6780KB,committed = 6780KB)<---线程堆栈使用的内存

    (malloc = 27KB,#66)

    (竞技场= 61KB,#30)<---资源和处理区域

  • 代码(保留= 102414KB,已提交= 6314KB)

    (malloc = 2574KB,#74316)

    (mmap:reserved = 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使用的不同内存区域的详细概述,还显示了保留和提交的内存.

我不知道一种技术可以为您提供更详细的内存消耗列表.

进一步阅读:

您还可以-XX:NativeMemoryTracking=detail与其他jcmd命令结合使用.可以在Java平台,标准版故障排除指南 - 2.6 jcmd实用程序中找到更详细的说明.您可以通过检查可能的命令"jcmd <pid> help"

  • “此版本中的NMT不会跟踪第三方本机代码内存分配和JDK类库。” (c)好,问题已解决:) (2认同)