症状
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 会推迟而在更大负载下再次失败;应定位持续增长的分配来源。