元数据
| id | netty-direct-memory-oom | 收录 | 2026-08-30 |
|---|---|---|---|
| 问题域 | 编码代理与终端 | 主题分组 | 构建与部署 |
| 适用工具 | jdk · 外部工具 | ||
症状
网关偶发 500 → 频繁:日志 `io.netty.util.internal.OutOfDirectMemoryError: failed to allocate N byte(s) of direct memory (used: X, max: Y)`,服务不可用、健康检查异常;堆内存与 GC 日志正常。
原因
直接内存(堆外)不受 GC 管理:`-XX:MaxDirectMemorySize` 未设置时默认 = `-Xmx`;自定义 Filter 无大小上限地缓存请求/响应体且释放依赖下游正常消费,异常/熔断时 ByteBuf 泄漏,最终顶满直接内存上限。
解法
1. 显式 `-XX:MaxDirectMemorySize`(堆与直接内存隔离),容器内存限制同步给足;
2. 请求体/响应体缓存加大小门槛,超限跳过;
3. 响应式链路补 `doFinally`/`onErrorResume` 兜底释放;
4. 开 `-Dio.netty.leakDetectionLevel=paranoid` 定位泄漏点;
5. 压测验证直接内存水位。
验证证据
- 机制实测(2026-08-30,WSL Ubuntu,OpenJDK 17.0.18):① 未设 MaxDirectMemorySize、`-Xmx64m` → 分配 64MB 直接内存后报 `OutOfMemoryError: Cannot reserve ... (allocated: 67108864, limit: 67108864)`,行为证明默认上限 = -Xmx;② `-XX:MaxDirectMemorySize=64m -Xmx256m` → 堆很空闲但直接内存照样 64MB OOM(直接内存独立于堆、不受 GC 管控);③ 显式 256m → 分配 200MB 成功。证据:实测复现日志(2026-08-30)。
- 未实测:网关 Filter/ByteBuf 泄漏完整复现(无 Spring Cloud Gateway 环境);Netty 的 `OutOfDirectMemoryError` 与 JDK `Direct buffer memory` 同机制,Netty 只是自定义了异常包装。
来源与证据
素材来源:https://www.cnblogs.com/zhangs1986/p/22555832
验证证据:Evidence details kept locally (2026-08-30)