You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编程检测java.lang.OutOfMemoryError: Direct buffer memory并生成Java堆转储

Java直接内存溢出(Direct buffer memory)自动生成堆转储方案

-XX:+HeapDumpOnOutOfMemoryError参数默认仅响应堆内存溢出场景,直接内存、元空间、栈溢出等非堆OOM场景默认不会触发堆转储生成。

对应的异常日志如下:

Sep 20 23:02:55 CKM01204505062-A control-path[128819]: 2021-09-20 23:02:55.266 [] [INFO] [com.emc.bedrock.http.HttpVerticle|vert.x-eventloop-thread-3]  Request ID: 2c7633a4-db9c-4ec5-b4ca-c93c47512384 completed in 4 ms.
Sep 20 23:02:55 CKM01204505062-A control-path[128199]: Exception in thread "iothread-2" java.lang.OutOfMemoryError: Direct buffer memory
Sep 20 23:02:55 CKM01204505062-A control-path[128199]:         at java.nio.Bits.reserveMemory(Bits.java:695)
Sep 20 23:02:55 CKM01204505062-A control-path[128199]:         at java.nio.DirectByteBuffer.(DirectByteBuffer.java:123)
Sep 20 23:02:55 CKM01204505062-A control-path[128199]:         at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
Sep 20 23:02:55 CKM01204505062-A control-path[128199]:         at zmq.DecoderBase.(DecoderBase.java:35)
Sep 20 23:02:55 CKM01204505062-A control-path[128199]:         at zmq.V1Decoder.(V1Decoder.java:21)
Sep 20 23:02:55 CKM01204505062-A control-path[128199]:         at zmq.StreamEngine.newDecoder(StreamEngine.java:102)
Sep 20 23:02:55 CKM01204505062-A control-path[128199]:         at zmq.StreamEngine.handshake(StreamEngine.java:549)
Sep 20 23:02:55 CKM01204505062-A control-path[128199]:         at zmq.StreamEngine.inEvent(StreamEngine.java:278)
Sep 20 23:02:55 CKM01204505062-A control-path[128199]:         at zmq.IOObject.inEvent(IOObject.java:86)
Sep 20 23:02:55 CKM01204505062-A control-path[128199]:         at zmq.Poller.run(Poller.java:228)
Sep 20 23:02:55 CKM01204505062-A control-path[128199]:         at java.lang.Thread.run(Thread.java:748)

解决方案

方案1:升级JDK版本+配置JVM参数(无代码侵入首选)

JDK 8u92及以上版本新增了-XX:+HeapDumpBeforeFullGC参数,搭配-XX:MaxDirectMemorySize指定直接内存上限,同时保留原有-XX:+HeapDumpOnOutOfMemoryError参数,当直接内存达到上限触发FullGC前会自动生成堆转储文件。
参数组合示例:

-Xmx10g -XX:MaxDirectMemorySize=2g -XX:+HeapDumpOnOutOfMemoryError -XX:+HeapDumpBeforeFullGC -XX:HeapDumpPath=/var/log/java_heapdump.hprof

可额外添加-XX:+ExitOnOutOfMemoryError参数,OOM发生后自动退出进程,避免服务假死。

方案2:自定义全局异常捕获主动触发转储

在应用启动时注册全局未捕获异常处理器,当捕获到对应OOM异常时主动调用HotSpot诊断接口生成堆转储,示例代码如下:

Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
    if (throwable instanceof OutOfMemoryError 
        && throwable.getMessage().contains("Direct buffer memory")) {
        // 主动生成堆转储
        try {
            String dumpPath = "/var/log/direct_oom_dump_" + System.currentTimeMillis() + ".hprof";
            com.sun.management.HotSpotDiagnosticMXBean bean = 
                ManagementFactory.getPlatformMXBean(com.sun.management.HotSpotDiagnosticMXBean.class);
            bean.dumpHeap(dumpPath, true);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 异常处理完成后退出进程,避免服务不可用
        System.exit(-1);
    }
});

如果使用JDK9及以上版本,需要额外添加JVM参数--add-exports jdk.management/com.sun.management.internal=ALL-UNNAMED才可以调用HotSpotDiagnosticMXBean接口。

方案3:系统日志监控触发jmap转储

编写shell脚本实时监控journalctl日志,匹配到直接内存OOM关键词时自动调用jmap生成堆转储,示例脚本片段如下:

journalctl -u 你的服务名 -f | while read line
do
    if [[ $line == *"java.lang.OutOfMemoryError: Direct buffer memory"* ]]; then
        # 从日志中提取Java进程PID,可根据实际日志格式调整提取规则
        PID=$(echo $line | grep -oP 'control-path\[\K[0-9]+' | head -n1)
        jmap -dump:format=b,file=/var/log/direct_oom_${PID}_$(date +%Y%m%d%H%M%S).hprof $PID
        # 可选:生成转储后停止服务避免异常扩散
        systemctl stop 你的服务名
        break
    fi
done

将该脚本配置为后台服务开机自启即可实现无侵入自动捕获。

内容的提问来源于stack exchange,提问作者mandingoteck

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 03:45:02