← 中文资源

简体中文版本

Java 报 OutOfMemoryError: Direct buffer memory

通过跟踪直接内存用量与 MaxDirectMemorySize(而非只看堆)诊断直接缓冲区耗尽。

阅读英文原文

症状

JVM 抛出 OutOfMemoryError: Direct buffer memory,而堆统计看起来健康。直接 ByteBuffer 位于堆外的本地内存,因此即便进程不断增长,堆转储也看不出问题。高吞吐的网络或文件 IO 会分配直接缓冲区,Netty 等池化分配器也是常见来源。

诊断

用 Native Memory Tracking 与 VM.native_memory summary 跟踪直接内存;对比堆与直接内存增长;临时提高 MaxDirectMemorySize 观察是否只是推迟。

java -XX:MaxDirectMemorySize=256m -XX:+PrintNMTStatistics -jar app.jar

根因

直接 ByteBuffer 的分配超过了 MaxDirectMemorySize,因为分配速度快于回收,或引用被长期持有,于是尽管堆健康,本地内存仍耗尽。

修复

释放或复用直接缓冲区,限制池化分配,并按真实负载设定 MaxDirectMemorySize。若用量持续增长,应追踪分配点查找引用存活过久的缓冲区,而不是只抬高上限。

验证

重跑负载,用本地内存摘要确认直接内存保持在上限内,并确认不再出现该 OutOfMemoryError。负载下本地内存稳定即证明修复。

常见陷阱

只抬高 MaxDirectMemorySize 会推迟而在更大负载下再次失败;应定位持续增长的分配来源。