WebFlux Web服务DirectByteBuffer分配OOM后恢复相关问题咨询
WebFlux文件上传堆外内存OOM问题解决方案
异常表现的核心原因
你遇到的两类问题均属于框架、JVM的默认行为,不属于Bug,是遗漏了大文件上传场景的适配配置导致的。
1. 首次OOM后持续不稳定问题
原因
- 你当前配置
-Dio.netty.maxDirectMemory=0会让Netty直接复用JDK的-XX:MaxDirectMemorySize阈值,Netty池化分配器触发OOM后不会主动回收内存池中的空闲缓存块,也不会做碎片整理,只有新请求的缓冲区大小刚好匹配残留空闲块时才能分配成功,否则直接抛OOM,就会出现部分请求正常、部分请求失败的表现。 @RequestPart注解接收Part参数时,Spring WebFlux默认会把整个上传文件的内容全量加载到内存中,大文件请求很容易快速占满堆外内存。
修复配置
- 新增参数
-Dio.netty.allocator.cacheTrimIntervalMillis=30000,定期清理Netty线程本地的空闲缓存块,降低内存碎片化概率。 - 调整内存阈值配置:将
-Dio.netty.maxDirectMemory设为比JDK堆外内存上限小20%的值,比如你设置-XX:MaxDirectMemorySize=1g,同步配置-Dio.netty.maxDirectMemory=800m,避免Netty占满所有堆外内存后触发不可恢复的JDK层面OOM。 - 代码层面改造:将
@RequestPart入参改为@RequestBody Flux<Part> parts,采用流方式边接收文件内容边转发到上游服务,不要全量缓存文件内容到内存。
2. 非池化模式下内存未归还操作系统问题
原因
该问题是JDK11默认使用的glibc内存分配器的特性,不是Netty问题:glibc默认会缓存释放的内存块用于后续分配,不会立即归还给操作系统,尤其是大内存分配场景下产生的内存碎片会被glibc长期持有,就会出现NMT显示内存已释放、htop显示RES内存居高不下的表现。
修复配置
- 新增JVM参数
-XX:+UseMallocRelease,JDK11及以上版本支持该参数,会强制glibc在内存释放后主动归还给操作系统。 - 调整
-Djdk.nio.maxCachedBufferSize参数到1m~2m,适配文件上传场景的大缓冲区分配需求,减少频繁的内存分配回收操作。 - 若使用Alpine基础镜像,可替换为jemalloc作为默认内存分配器,内存释放效率更高。
内容的提问来源于stack exchange,提问作者JCMS
相关产品推荐
相关产品推荐

