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

时间:2014-09-25 14:26:54

标签: java linux unix memory

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

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 ]

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

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

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

2 个答案:

答案 0 :(得分:14)

我遇到了同样的问题。这是glibc> = 2.10

的已知问题

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

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

Google for 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

答案 1 :(得分:5)

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

打开ZipInputStream的典型方式是致电Class.getResource / ClassLoader.getResource并在openConnection().getInputStream()实例上调用java.net.URL或致电{ {1}} / Class.getResourceAsStream。必须确保这些流始终关闭。

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

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

同一博客还包含有关其他native memory leak related to ByteBuffers的信息。 Java 8u102有一个特殊的系统属性MALLOC_CONF,用于限制该博客帖子中描述的缓存问题。

jdk.nio.maxCachedBufferSize

总是检查打开文件句柄以查看内存泄漏是否是由大量mmap:ed文件引起的。在Linux上-Djdk.nio.maxCachedBufferSize=262144 可用于列出打开的文件和打开套接字:

lsof

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

lsof -Pan -p PID

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

pmap -x PID

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

还有Native Memory Tracking (NMT) in the JVM。这可能有助于检查JVM本身是否正在耗尽本机内存。

jattach tool也可以在容器化(docker)环境中用于触发来自主机的threaddumps或heapdumps。它还能够运行控制NMT所需的jcmd命令。