Flux<DataBuffer>引发ByteBuf内存泄漏,求解决方案
解决ByteBuf未释放的内存泄漏问题
问题根源
你当前的代码只释放了blockLast()获取到的最后一个DataBuffer,但Flux<DataBuffer>流中的其他缓冲区在正常写入、超时或异常场景下可能没有被释放。DataBufferUtils.write默认不会自动释放写入后的DataBuffer,仅手动处理最后一个元素远远不够,这就是导致ByteBuf.release() was not called before it's garbage-collected异常的原因。
修复方案
1. 启用自动释放+兜底丢弃处理
修改代码,利用DataBufferUtils.write的重载方法开启自动释放,并添加doOnDiscard确保异常/中断场景下的缓冲区也能被释放:
private File createFileFromDataBuffer(Flux<DataBuffer> dataBuffer, String fileName, int timeoutInMin) { File tempFile = null; try { Path tempDir = Files.createTempDirectory("xyz"); tempFile = new File(tempDir.toFile(), fileName); try (OutputStream os = new FileOutputStream(tempFile)) { DataBufferUtils.write(dataBuffer, os, true) // 兜底处理:任何被丢弃的DataBuffer都会被释放 .doOnDiscard(DataBuffer.class, DataBufferUtils::release) .blockLast(Duration.ofMinutes(timeoutInMin)); } } catch (IOException e) { log.error("Error in API", e); } return tempFile; }
关键修改说明
autoRelease=true:DataBufferUtils.write的第三个参数设为true后,每个DataBuffer成功写入输出流后会自动调用DataBufferUtils.release()释放,覆盖正常流程下的释放需求。doOnDiscard:处理超时、IO异常等中断场景中未被正常处理的DataBuffer,确保这些缓冲区不会被遗漏,彻底避免内存泄漏。- 移除了不必要的
share()调用:blockLast是唯一订阅者,共享流没有意义,反而可能引入额外的订阅问题。 - 删除了手动保存和释放
dataBufferTemp的逻辑:自动释放已经处理了所有DataBuffer,手动释放反而可能导致重复释放的错误。
额外注意事项
- 始终使用
DataBufferUtils工具类来释放DataBuffer,不要直接调用ByteBuf的release()方法——不同的DataBuffer实现(比如Netty的NettyDataBuffer)有特定的释放逻辑,工具类会统一处理。 - 如果流中存在异常终止的情况,确保所有分支都能触发缓冲区释放,
doOnDiscard是可靠的兜底手段。
内容的提问来源于stack exchange,提问作者Raghav Agarwal
相关产品推荐
相关产品推荐

