Java 进程的常驻内存使用量 (RSS) 不断增长
- 2024-10-10 09:28:00
- admin 原创
- 177
问题描述:
我们最近对生产系统的观察表明,Java 容器的常驻内存使用量正在增长。关于这个问题,我们使用 pmap 等一些本机工具进行了一些调查,以了解为什么 java 进程消耗的内存比堆 + 线程堆栈 + 共享对象 + 代码缓存 + 等多得多。结果,我们发现本机进程(可能使用 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 (Final) 64 位架构和 JDK 1.7.0_17 。
问题是,这些块是什么?哪个子系统分配这些块?
更新:我们不使用 JIT 和/或 JNI 本机代码调用。
解决方案 1:
也可能存在本机内存泄漏。一个常见问题是由于未关闭ZipInputStream
/而导致的本机内存泄漏GZIPInputStream
。
打开的典型方式ZipInputStream
是通过调用Class.getResource
/ClassLoader.getResource
并调用openConnection().getInputStream()
实例java.net.URL
或通过调用Class.getResourceAsStream
/ ClassLoader.getResourceAsStream
。必须确保这些流始终被关闭。
一些常用的开源库存在泄漏未关闭的java.util.zip.Inflater
或java.util.zip.Deflater
实例的错误。例如,Nimbus Jose JWT 库已在 6.5.1 版本中修复了相关的内存泄漏。Java JWT (jjwt) 有一个类似的错误,已在 0.10.7 版本中修复。这两个案例中的错误模式是,当提供/实例时,调用DeflaterOutputStream.close()
和InflaterInputStream.close()
不调用Deflater.end()
/ 。在这些情况下,仅检查代码中是否关闭了流是不够的。代码中创建的每个/实例都必须有被调用的处理。Inflater.end()
`DeflaterInflater
DeflaterInflater
.end()`
检查 Zip*Stream 泄漏的一种方法是获取堆转储并搜索名称中带有“zip”、“Inflater”或“Deflater”的任何类的实例。这在许多堆转储分析工具(如 Yourkit Java Profiler、JProfiler 或 Eclipse MAT)中都是可能的。还值得检查处于最终状态的对象,因为在某些情况下,内存仅在最终确定后才释放。检查可能使用本机库的类很有用。这也适用于 TLS/ssl 库。
Elastic有一个名为leakchecker的 OSS 工具,它是一个 Java 代理,可用于查找java.util.zip.Inflater
尚未关闭(.end()
未调用)的实例的来源。
对于一般的本机内存泄漏(不仅仅是 zip 库泄漏),您可以使用jemalloc来调试本机内存泄漏,方法是通过指定MALLOC_CONF
环境变量中的设置来启用 malloc 采样分析。详细说明请参阅此博客文章:http://www.evanjones.ca/java-native-leak-bug.html。此博客文章还包含有关使用 jemalloc 调试 Java 应用程序中的本机内存泄漏的信息。Elastic的一篇博客文章介绍了 jemalloc 并提到了leakchecker,这是 Elastic 开源的工具,用于追踪未关闭的 zip inflater 资源导致的问题。
还有一篇博客文章介绍了与 ByteBuffers 相关的本机内存泄漏。Java 8u102具有特殊的系统属性jdk.nio.maxCachedBufferSize
来限制该博客文章中描述的缓存问题。
-Djdk.nio.maxCachedBufferSize=262144
最好始终检查打开的文件句柄,以查看内存泄漏是否由大量 mmap:ed 文件引起。在 Linux 上,lsof
可用于列出打开的文件和打开的套接字:
lsof -Pan -p PID
进程内存映射的报告也可以帮助调查本机内存泄漏
pmap -x PID
对于在 Docker 中运行的 Java 进程,应该可以在“主机”上执行 lsof 或 pmap 命令。您可以使用此命令找到容器化进程的 PID
docker inspect --format '{{.State.Pid}}' container_id
获取线程转储(或使用 jconsole/JMX)来检查线程数也很有用,因为每个线程都会为其堆栈消耗 1MB 的本机内存。大量线程会占用大量内存。
JVM 中还有本机内存跟踪 (NMT) 。这可能有助于检查 JVM 本身是否正在耗尽本机内存。
AsyncProfiler 可用于检测本机内存分配的来源。这在另一个答案中进行了解释。
jattach 工具还可用于容器化 (docker) 环境,以从主机触发线程转储或堆转储。它还能够运行控制 NMT 所需的 jcmd 命令。
解决方案 2:
我遇到了同样的问题。这是 glibc >= 2.10 的一个已知问题
解决方法是设置此环境变量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 搜索 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
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件