java - JVM 中不断增长的常驻大小集

标签 java linux memory jvm

我有一个在 64 位 LINUX 上运行的 JAVA 进程,版本为“CentOS Linux 版本 7.3.1611”,RAM 为 7.6GB。
下面是一些使用过的 JVM 标志,

  • -Xmx3500m
  • -Xms3500m
  • -XX:MaxMetaspaceSize=400m
  • -XX:CompressedClassSpaceSize=35m

  • 注意:线程栈(1MB)和代码缓存(240MB)的大小为默认值,JDK版本为1.8.0_252。
    在运行 TOP 命令时,它观察到我的 6.3 GB RAM 由 java
    过程。
    PR   NI    VIRT     RES    SHR S  %CPU %MEM   TIME+   COMMAND   
    20   0  28.859g  6.341g  22544 S 215.2 83.1   4383:23 java    
    
    我尝试使用 JCMD、JMAP 和 JSTAT 命令分析 JVM 的 native 内存。
    JMAP -heap 命令的输出:
    Debugger attached successfully.
    Server compiler detected.
    JVM version is 25.252-b14
    
    using thread-local object allocation.
    Garbage-First (G1) GC with 33 thread(s)
    
    Heap Configuration:
       MinHeapFreeRatio         = 40
       MaxHeapFreeRatio         = 70
       MaxHeapSize              = 3670016000 (3500.0MB)
       NewSize                  = 1363144 (1.2999954223632812MB)
       MaxNewSize               = 2202009600 (2100.0MB)
       OldSize                  = 5452592 (5.1999969482421875MB)
       NewRatio                 = 2
       SurvivorRatio            = 8
       MetaspaceSize            = 21807104 (20.796875MB)
       CompressedClassSpaceSize = 36700160 (35.0MB)
       MaxMetaspaceSize         = 419430400 (400.0MB)
       G1HeapRegionSize         = 1048576 (1.0MB)
    
    Heap Usage:
    G1 Heap:
       regions  = 3500
       capacity = 3670016000 (3500.0MB)
       used     = 1735444208 (1655.048568725586MB)
       free     = 1934571792 (1844.951431274414MB)
       47.28710196358817% used
    G1 Young Generation:
    Eden Space:
       regions  = 1311
       capacity = 2193620992 (2092.0MB)
       used     = 1374683136 (1311.0MB)
       free     = 818937856 (781.0MB)
       62.66730401529637% used
    Survivor Space:
       regions  = 113
       capacity = 118489088 (113.0MB)
       used     = 118489088 (113.0MB)
       free     = 0 (0.0MB)
       100.0% used
    G1 Old Generation:
       regions  = 249
       capacity = 1357905920 (1295.0MB)
       used     = 241223408 (230.04856872558594MB)
       free     = 1116682512 (1064.951431274414MB)
       17.76436824135799% used
    
    485420 interned Strings occupying 83565264 bytes.
    
    JSTAT -gc 命令的输出:
     S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
     0.0   33792.0  0.0   33792.0 1414144.0 1204224.0 2136064.0  1558311.7  262872.0 259709.5 19200.0 18531.5  22077  985.995  10     41.789 1027.785
     0.0   33792.0  0.0   33792.0 1414144.0 1265664.0 2136064.0  1558823.7  262872.0 259709.5 19200.0 18531.5  22077  985.995  10     41.789 1027.785
     0.0   63488.0  0.0   63488.0 124928.0 32768.0  3395584.0  1526795.8  262872.0 259709.5 19200.0 18531.5  22078  986.041  10     41.789 1027.830
     0.0   63488.0  0.0   63488.0 124928.0 49152.0  3395584.0  1526795.8  262872.0 259709.5 19200.0 18531.5  22078  986.041  10     41.789 1027.830
     0.0   63488.0  0.0   63488.0 124928.0 58368.0  3395584.0  1526795.8  262872.0 259709.5 19200.0 18531.5  22078  986.041  10     41.789 1027.830
    
    甚至 的输出产生的总和“JCMD pid VM.native_memory 摘要”大约是 5.0GB,甚至不接近 6.3GB。所以我找不到余额 1.3GB 的用途。
    我试图找出 6.3GB 是如何与 JVM 实际映射的。所以我决定检查/proc/pid 文件夹。
    在/proc/pid/status 文件中,
    VmRSS   : 6649680 kB 
    RssAnon :   6627136 kB
    RssFile :     22544 kB
    RssShmem:         0 kB 
    
    由此我发现6.3GB空间大部分都被匿名空间占用了。
    PMAP 命令的输出(截断):
    Address           Kbytes     RSS   Dirty Mode  Mapping
    0000000723000000 3607296 3606076 3606076 rw---   [ anon ]
    00000007ff2c0000   12544       0       0 -----   [ anon ]
    00007f4584000000     132       4       4 rw---   [ anon ]
    00007f4584021000   65404       0       0 -----   [ anon ]
    00007f4588000000     132      12      12 rw---   [ anon ]
    00007f4588021000   65404       0       0 -----   [ anon ]
    00007f458c000000     132       4       4 rw---   [ anon ]
    00007f458c021000   65404       0       0 -----   [ anon ]
    00007f4590000000     132       4       4 rw---   [ anon ]
    00007f4590021000   65404       0       0 -----   [ anon ]
    00007f4594000000     132       8       8 rw---   [ anon ]
    00007f4594021000   65404       0       0 -----   [ anon ]
    00007f4598000000     132       4       4 rw---   [ anon ]
    00007f4598021000   65404       0       0 -----   [ anon ]
    00007f459c000000    2588    2528    2528 rw---   [ anon ]
    
    
    我发现第一个匿名地址可能映射到堆内存,因为它的大小为 3.4GB。但是,我无法找到匿名空间的其余部分是如何使用的。
    我需要帮助找出 JVM 进程如何使用额外的 1.3 GB。
    除了 native 内存跟踪中提到的之外,任何有关 JVM 使用的内存的信息都将不胜感激。

    最佳答案

    正如所讨论的 here ,除了 Native Memory Tracking 覆盖的区域,JVM 进程中还有其他消耗内存的东西。
    许多大小正好为 64MB 的匿名区域(如您的 pmap 输出中)表明这些是 malloc arenas .已知标准 glibc 分配器具有 issues内存使用过多,尤其是在具有许多线程的应用程序中。我建议使用 jemalloc (或 tcmallocmimalloc )作为标准分配器的替代品 - 它没有提到的泄漏。另一种解决方案是使用 MALLOC_ARENA_MAX 限制 malloc arenas 的数量。环境变量。
    如果切换到 jemalloc 后问题仍然存在,这很可能是 native 内存泄漏的迹象。例如,Java 应用程序中的 native 泄漏可能是由

  • 未关闭的资源/流:ZipInputStream , DirectoryStream , Inflater , Deflater
  • JNI 库和代理库,包括标准 jdwp代理
  • improper bytecode instrumentation

  • 要查找泄漏源,您也可以使用 jemalloc其内置 profiling feature .然而,jemalloc无法展开 Java 堆栈跟踪。
    async-profiler可以显示混合的 Java+ native 堆栈。虽然它的主要目的是 CPU 和分配分析,但 async-profiler 也可以帮助 find native memory leaks在 Java 应用程序中。
    有关详细信息和更多示例,请参阅我的 Memory Footprint of a Java Process介绍。

    关于java - JVM 中不断增长的常驻大小集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63699573/

    相关文章:

    java - 在文件中存储具有相同键的多个数据并从 shell 脚本获取值?

    php模拟用户

    c++ - 如何让 Cmake 包含 gl/GL.h?

    java - 仅针对特定线程的条件代码同步

    java - 黑莓应用程序自动更新

    multithreading - 如何确定进程中每个线程的内存消耗?

    C++链表内存泄漏

    objective-c - 用随机字节填充内存 - C/Objective-C

    java - 使用 Java 的 struts2 中的浏览器区域设置

    linux - shell 中的 "invalid arithmetic operator"