当前位置:首页 > 问答 > 正文

JVM 堆外内存泄漏排查全流程记录

JVM | 堆外内存泄漏排查全流程记录

关键词与核心内容

  1. 堆外内存定义

    • Direct ByteBuffer、JNI调用、Native代码分配的内存
    • 不受JVM垃圾回收管理,需手动释放或依赖Cleaner机制
  2. 泄漏表现

    • 物理内存持续增长,但JVM堆内存(-Xmx)稳定
    • OOM Killer终止进程(Linux环境)
    • 监控工具显示堆外内存占用异常(如NMT、pmap)
  3. 排查工具

    JVM 堆外内存泄漏排查全流程记录

    • NMT(Native Memory Tracking)
      • JVM参数:-XX:NativeMemoryTracking=detail
      • 命令:jcmd <pid> VM.native_memory detail
    • pmap
      • 命令:pmap -x <pid> 查看进程内存映射
    • gdb

      分析Native内存地址(需结合符号表)

    • jemalloc/jeprof

      替换glibc,生成内存分配火焰图

  4. 常见泄漏场景

    • Direct ByteBuffer未释放
      • 未调用((DirectBuffer) buffer).cleaner().clean()
    • JNI库泄漏

      Native代码未释放malloc分配的内存

    • Netty等框架的PooledByteBuf
      • 未执行release()导致池化内存堆积
  5. 定位步骤

    • 步骤1:NMT对比基线与泄漏时差异
      • 关注Internal(committed/reserved)Direct部分
    • 步骤2:pmap定位可疑内存块

      查找匿名映射(anon)增长区域

      JVM 堆外内存泄漏排查全流程记录

    • 步骤3:堆转储分析

      使用Eclipse MAT检查DirectByteBuffer引用链

    • 步骤4:Native代码审查

      结合gdb或Valgrind检查JNI调用

  6. 修复与预防

    • 显式调用System.gc()触发Cleaner(临时方案)
    • 监控堆外内存指标(如JMX的BufferPoolMXBean
    • 限制Direct内存大小:-XX:MaxDirectMemorySize

典型日志/输出片段

--- NMT输出示例 ---  
[0x00007fbd34c00000 - 0x00007fbd38c00000] reserved 65536KB for Internal  
                          committed 61440KB from [0x00007fbd34c00000 - 0x00007fbd38800000]  
--- pmap异常片段 ---  
00007fbd38800000 10240K rw--- [ anon ]  <-- 可疑增长区域  

基于2025年8月前的技术实践整理,具体工具参数可能随版本迭代调整。

发表评论