java进程被linux oomkiller杀死,就像本机内存泄漏一样

java process killed by linux oomkiller, like native memory leak

提问人:hehe 提问时间:10/27/2023 最后编辑:hehe 更新时间:10/27/2023 访问量:58

问:

我有一个 Java 服务,已经运行了大约十天。 我发现它在繁忙时期被 Linux 的 OOM 杀手杀死了。我为它配置的堆内存是 Xmx10G Xms6G,但 OOM 杀手显示它的 RSS 是 24.5G。

[6252128.258453]Out of memory: Kill process 113627 (java) score 350 or sacrifice child
[6252128.258533]Killed process 113627 (java) total-vm:50134728kB, anon-rss:25062168kB, file-rss:0kB, shmem-rss:0kB
[7954659.707880][43116(bkmonitorbeat)]:gsch scan(inode=411811729,type=1,flags=0x0) -interrupted & wait(timeout=1000)
[7954659.709606][43116(bkmonitorbeat): gsch_scan(inode=411811729,type-1,flags-exe)-interrupted & waitdone

我重新启动了该过程,几天后发现顶部的RSS是30G。 我怀疑存在堆外内存泄漏。

我执行了jmap dump、jstack、pmap等操作,发现在这个过程中保存了大量的65508KB内存。 然后,我在 jmap 中发现了许多 java.lang.ref.Finalizer 对象,总共 7206 个。

enter image description here

进一步使用 OQL 查询,我发现 Finalizer 中的许多引用是 org.apache.commons.dbcp2.DelegatingPreparedStatement (2124),

enter image description here

org.apache.commons.dbcp2.DelegatingStatement (1940年),

enter image description here

sun.security.ssl.SSLSessionImpl (460)。

enter image description here

FinalizerThread 卡在 ReferenceQueue.remove() 处,感觉这个队列里什么都没有了,但是 Finalizer 的链表里还保留着很多垃圾。


"Finalizer" #3 daemon prio=8 os_prio=0 tid=0x00007f96183e2800 nid=0x174a7 in Object.wait() [0x00007f95e4ecd000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    - locked <0x0000000540020d40> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

我检查了smaps文件,发现有322个内存块,RSS值在64MB左右,累积到20GB以上。

enter image description here

我使用 gdb dump an 64M 内存到文件,但我不知道内存数据结构,所以我无法调试它。

这意味着内存泄漏可能与 glibc 的 malloc 内存池有关。

enter image description here

ldd /usr/lib64/jdk8/bin/java  

linux-vdso.so.1 =>  (0x00007ffd381f1000)
libpthread.so.0 => /lib64/libpthread.so.0(0x00007fc9c1743000)
libjli.so => /usr/lib64/idk8/bin/../lib/amd64/ili/libjli.so(0x00007fc9c152d000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fc9c1329000)
libc.so.6 => /lib64/ibc.so.6 (0x00007fc9cof5b000)
/lib64/ld-linux-x86-64.so.2 (0x00007fc9c195f000)



-------
Installed Packages
glibc.x86_64  2.17-317.el

我的流程环境没有MALLOC_ARENA_MAX

我手动重启了服务,防止 OOM killer 再次杀死它,并添加了 -XX:NativeMemoryTracking=detail 参数,但是运行了几天后,使用时仍然看不到任何异常。jcmd pid VM.native_memory detail

enter image description here

我还有一些其他调试信息 接下来我应该做些什么来解决这个问题?

Java Linux JVM OOM

评论

0赞 hehe 10/27/2023
调试信息:drive.google.com/drive/folders/...
0赞 Stephen C 10/27/2023
看起来您的内存泄漏实际上是资源泄漏。某些东西没有关闭数据库连接或语句,它们最终会进入终结器队列。终结器线程要么跟不上,要么被阻塞。检查执行数据库操作的应用程序代码,以确保连接/语句/结果集不会泄漏。
0赞 hehe 10/27/2023
为什么 FinalizerThread 队列被阻止。
0赞 Stephen C 10/27/2023
没有足够的信息来说明原因。但它并不真正相关。您的代码首先不应该泄漏 DB/JDBC 资源。
1赞 Stephen C 10/27/2023
当抛出异常时,您是否也关闭了数据库资源?您正在使用而不是尝试使用资源这一事实是可疑的。closeQuietly

答: 暂无答案