美文网首页
(13)堆外内存 OOM

(13)堆外内存 OOM

作者: hedgehog1112 | 来源:发表于2020-12-14 10:27 被阅读0次

内存使用率不断上升,开始用 SWAP 内存,同时 GC 时间飙升,线程 Block ,top 命令发现 Java 进程RES 超过-Xmx 大小。确定堆外内存泄漏

ps:RES:resident memory usage 常驻内存:

    1、进程当前用的内存大小,包含其他进程共享,不包括swap out

    2、如申请100m的内存,实际用10m,只增长10m,与VIRT相反

    3、统计加载的库文件所占内存大小

一、主要两种原因:

1)通过 UnSafe#allocateMemory,ByteBuffer#allocateDirect 主动申请堆外内存没释放,常见于 NIO、Netty 等相关组件。

2)代码通过 JNI 调用 Native Code 申请内存没释放

二、策略

哪种原因造成的堆外内存泄漏?

    1)用 NMT(NativeMemoryTracking) 分析。在项目中添加 -XX:NativeMemoryTracking=detail JVM参数重启项目(NMT 会带来 5%~10% 的性能损耗)。

    2)用命令 jcmd pid VM.native_memory detail 查看内存分布。重点观察 total 中的 committed,因为 jcmd 命令显示的内存包含堆内内存、Code 区域、通过 Unsafe.allocateMemory 和 DirectByteBuffer 申请的内存,但不包含其他 Native Code(C 代码)申请的堆外内存。

total 中 committed 和 top 中的 RES 相差不大,为主动申请未释放,相差较大,JNI 调用造成的

原因一:主动申请未释放

1、控制申请最大值 -XX:MaxDirectMemorySize=size 默认和 -Xmx 相等

2、NIO 和 Netty 都取 -XX:MaxDirectMemorySize 值限制大小。NIO 和 Netty 有计数器字段,计算已申请堆外内存大小,监控堆外内存使用情况,超过最大值限制,抛OOM

    ps:NIO 中是 java.nio.Bits#totalCapacity、Netty中 io.netty.util.internal.PlatformDependent#DIRECT_MEMORY_COUNTER。

    NIO 中是:OutOfMemoryError: Direct buffer memory。

    Netty 中是:OutOfDirectMemoryError: failed to allocate capacity byte(s) of direct memory (used: usedMemory , max: DIRECT_MEMORY_LIMIT )。

3、解决:Debug确定是否释放内存。另外检查是否有System.gc

原因二:JNI 调 Native Code 申请的内存未释放

排查困难, Google perftools + Btrace分析问题代码在哪

gperftools 是 Google 开发的一款非常实用的工具集,它的原理是在 Java 应用程序运行时,当调用 malloc 时换用它的 libtcmalloc.so,这样就能对内存分配情况做一些统计。我们使用 gperftools 来追踪分配内存的命令。如下图所示,通过 gperftools 发现 Java_java_util_zip_Inflater_init 比较可疑。

接下来可以使用 Btrace,尝试定位具体的调用栈。Btrace 是 Sun 推出的一款 Java 追踪、监控工具,可以在不停机的情况下对线上的 Java 程序进行监控。如下图所示,通过 Btrace 定位出项目中的 ZipHelper 在频繁调用 GZIPInputStream ,在堆外内存分配对象。

最终定位到是,项目中对 GIPInputStream 的使用错误,没有正确的 close()。

除了项目本身的原因,还可能有外部依赖导致的泄漏,如 Netty 和 Spring Boot,详细情况可以学习下这两篇文章:《疑案追踪:Spring Boot内存泄露排查记》、《Netty堆外内存泄露排查盛宴》。

总结

用 NMT + jcmd 分析泄漏的堆外内存是哪里申请,确定原因后,用不同手段,进行原因定位

https://mp.weixin.qq.com/s/RFwXYdzeRkTG5uaebVoLQw

相关文章

  • (13)堆外内存 OOM

    内存使用率不断上升,开始用 SWAP 内存,同时 GC 时间飙升,线程 Block ,top 命令发现 Java ...

  • 对于OOM的理解

    OOM,即OutOfMemory,内存溢出 OOM之 Java heap spacejava堆内存溢出,一般由于内...

  • OutOfMemoryError

    jvm规定,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OOM的可能。 1、堆内存益处 内存益处: 内...

  • Spark异常处理——OOM

    堆内存溢出 错误提示 解决 内存不够,数据太多就会抛出OOM的Exeception,主要有driver OOM和e...

  • -XX:HeapDumpOnOutOfMemoryError

    用法:-XX:+HeapDumpOnOutOfMemoryError 当堆抛出OOM错误时,dump出当前的内存堆...

  • Java 堆外内存回收原理,内存溢出OOM场景

    1、堆外内存简介: DirectByteBuffer 这个类是 JDK 提供使用堆外内存的一种途径,当然常见的业务...

  • 直接内存与 JVM 源码分析

    直接内存(堆外内存) 直接内存有一种叫法,堆外内存。 直接内存(堆外内存)指的是 Java 应用程序通过直接方式从...

  • 第1篇 JVM相关

    JVM 堆、栈区、本地内存 JVM内存 线程共享区 JAVA堆 方法区,如果耗尽会抛出OOM异常Out of Me...

  • 溢出泄露

    内存溢出 oom 1、Java heap space :堆内存溢出弱引用:垃圾回收时,无论内存是否充足,都会回收被...

  • Java OOM

    OOM类型:1.java.lang.OutOfMemoryError: Java heap space堆内存不足:...

网友评论

      本文标题:(13)堆外内存 OOM

      本文链接:https://www.haomeiwen.com/subject/ttheiktx.html