增加Java Process的驻留内存使用量(RSS)

Erh*_*mir 12 java unix linux memory

我们最近对生产系统的观察告诉我们Java容器的驻留内存使用量增长了.关于这个问题,我们已经做了一些调查,以了解为什么java进程使用像pmap这样的本机工具消耗比Heap + Thread Stacks + Shared Objects + Code Cache +等更多的内存.结果,我们发现了一些由本机进程分配的64M内存块(成对)(可能使用malloc/mmap):

0000000000400000      4K r-x--  /usr/java/jdk1.7.0_17/bin/java
0000000000600000      4K rw---  /usr/java/jdk1.7.0_17/bin/java
0000000001d39000   4108K rw---    [ anon ]
0000000710000000  96000K rw---    [ anon ]
0000000715dc0000  39104K -----    [ anon ]
00000007183f0000 127040K rw---    [ anon ]
0000000720000000 3670016K rw---    [ anon ]
00007fe930000000  62876K rw---    [ anon ]
00007fe933d67000   2660K -----    [ anon ]
00007fe934000000  20232K rw---    [ anon ]
00007fe9353c2000  45304K -----    [ anon ]
00007fe938000000  65512K rw---    [ anon ]
00007fe93bffa000     24K -----    [ anon ]
00007fe940000000  65504K rw---    [ anon ]
00007fe943ff8000     32K -----    [ anon ]
00007fe948000000  61852K rw---    [ anon ]
00007fe94bc67000   3684K -----    [ anon ]
00007fe950000000  64428K rw---    [ anon ]
00007fe953eeb000   1108K -----    [ anon ]
00007fe958000000  42748K rw---    [ anon ]
00007fe95a9bf000  22788K -----    [ anon ]
00007fe960000000   8080K rw---    [ anon ]
00007fe9607e4000  57456K -----    [ anon ]
00007fe968000000  65536K rw---    [ anon ]
00007fe970000000  22388K rw---    [ anon ]
00007fe9715dd000  43148K -----    [ anon ]
00007fe978000000  60972K rw---    [ anon ]
00007fe97bb8b000   4564K -----    [ anon ]
00007fe980000000  65528K rw---    [ anon ]
00007fe983ffe000      8K -----    [ anon ]
00007fe988000000  14080K rw---    [ anon ]
00007fe988dc0000  51456K -----    [ anon ]
00007fe98c000000  12076K rw---    [ anon ]
00007fe98cbcb000  53460K -----    [ anon ]
Run Code Online (Sandbox Code Playgroud)

我用0000000720000000 3670016K解释该行是指堆空间,我们使用JVM参数"-Xmx"定义其大小.在那之后,对开始,其总和是64M.我们正在使用CentOS版本5.10(最终版)64位arch和JDK 1.7.0_17.

问题是,那些街区是什么?哪个子系统分配这些?

更新:我们不使用JIT和/或JNI本机代码调用.

Lar*_*ari 16

我遇到了同样的问题.这是glibc> = 2.10的已知问题

解决方法是设置此env变量 export MALLOC_ARENA_MAX=4

关于设置MALLOC_ARENA_MAX的IBM文章 https://www.ibm.com/developerworks/community/blogs/kevgrig/entry/linux_glibc_2_10_rhel_6_malloc_may_show_excessive_virtual_memory_usage?lang=en

谷歌为MALLOC_ARENA_MAX或在SO上搜索它以找到很多参考.

您可能还想调整其他malloc选项以优化分配内存的低碎片:

# tune glibc memory allocation, optimize for low fragmentation
# limit the number of arenas
export MALLOC_ARENA_MAX=2
# disable dynamic mmap threshold, see M_MMAP_THRESHOLD in "man mallopt"
export MALLOC_MMAP_THRESHOLD_=131072
export MALLOC_TRIM_THRESHOLD_=131072
export MALLOC_TOP_PAD_=131072
export MALLOC_MMAP_MAX_=65536
Run Code Online (Sandbox Code Playgroud)

  • Java 8中存在一个JVM错误,导致无限制的本机内存增长:http://bugs.java.com/bugdatabase/view_bug.do?video_id = JDK-8164293 - 如果这对您有影响,可以使用`MALLOC_ARENA_MAX`减慢你的记忆力增长,但不能完全解决问题. (6认同)

Lar*_*ari 7

也可能存在本机内存泄漏.常见问题是由于未关闭ZipInputStream/ 而导致的本机内存泄漏GZIPInputStream.

一个典型的方法ZipInputStream是打开是一个呼叫Class.getResource/ ClassLoader.getResource并呼吁openConnection().getInputStream()java.net.URL实例或致电Class.getResourceAsStream/ ClassLoader.getResourceAsStream.必须确保这些流始终关闭.

检查Zip*Stream泄漏的一种方法是获取堆转储并搜索名称中带有"zip","Inflater"或"Deflater"的任何类的实例.这在许多堆转储分析工具中是可能的,例如Yourkit Java Profiler,JProfiler或Eclipse MAT.在完成状态下检查对象也是值得的,因为在某些情况下,只有在完成后才释放内存.检查可能使用本机库的类很有用.这也适用于TLS/ssl库.

您可以通过指定环境变量中的设置来启用malloc采样分析,从而使用jemalloc来调试本机内存泄漏java.util.zip.Inflater.此博客文章中提供了详细说明:http://www.evanjones.ca/java-native-leak-bug.html.此博客文章还提供了有关使用jemalloc调试Java应用程序中的本机内存泄漏的信息.

同一博客还包含有关与ByteBuffers相关的另一个本机内存泄漏的信息.Java 8u102有一个特殊的系统属性java.util.zip.Deflater来限制该博客文章中描述的缓存问题.

-Djdk.nio.maxCachedBufferSize=262144
Run Code Online (Sandbox Code Playgroud)

始终检查打开的文件句柄以查看内存泄漏是否是由大量mmap:ed文件引起的.在Linux DeflaterOutputStream.close()上可以用来列出打开的文件和打开的套接字:

lsof -Pan -p PID
Run Code Online (Sandbox Code Playgroud)

该进程的内存映射报告还可以帮助调查本机内存泄漏

pmap -x PID
Run Code Online (Sandbox Code Playgroud)

对于在Docker中运行的Java进程,应该可以在"host"上执行lsof或pmap命令.您可以使用此命令找到容器化过程的PID

docker inspect --format '{{.State.Pid}}' container_id
Run Code Online (Sandbox Code Playgroud)

获取线程转储(或使用jconsole/JMX)来检查线程数也很有用,因为每个线程为其堆栈消耗1MB的本机内存.大量线程会占用大量内存.

JVM中还有本机内存跟踪(NMT).这可能有助于检查JVM本身是否正在耗尽本机内存.

所述jattach工具也可用于在集装箱(搬运工)环境,以触发从主机threaddumps或heapdumps.它还能够运行控制NMT所需的jcmd命令.