You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Netty writeAndFlush操作引发内存泄漏问题排查求助

Netty内存泄漏排查:Unpooled ByteBuf在writeAndFlush后泄漏问题

问题场景

开发基于Netty的类SignalR Java包,压测时发现内存泄漏,定位到回写客户端结果的writeMessageInternal方法:调用channel.writeAndFlush(buf)时出现泄漏,注释该行则无泄漏。buf是Unpooled ByteBuf,环境为Java 21 + netty-all 4.1.58.Final。

泄漏代码:

private ChannelFuture writeMessageInternal(Message message) {
        ByteBuf buf;
        Codec codec = message.getCodec();
        try {
            buf = codec.encode(message);
        } catch (Exception e) {
            throw new RuntimeException();
        }
        ChannelFuture channelFuture = channel.writeAndFlush(buf);
        return channelFuture;
    }

可能的原因及排查方案

1. ChannelFuture被长期持有导致ByteBuf无法回收

Netty在调用writeAndFlush后,会在IO操作完成后自动释放Unpooled ByteBuf,但如果上层代码长期持有返回的ChannelFuture(比如存入静态集合、作为长生命周期对象的成员变量),ChannelFuture会关联ByteBuf的引用,导致GC无法回收。

排查&解决:

  • 检查上层调用writeMessageInternal的代码,确认是否长期保留了ChannelFuture实例。
  • 可以给ChannelFuture添加完成监听器,主动确认ByteBuf状态,即使自动释放失效也能手动兜底:
channelFuture.addListener(future -> {
    if (!buf.isReleased()) {
        buf.release();
        // 打印日志记录未释放情况,便于排查
    }
});

2. Netty版本与Java 21的兼容性问题

Netty 4.1.58.Final发布于2021年,而Java 21是2023年推出的版本,两者可能存在内存管理(如ZGC/Shenandoah GC)的兼容性bug,导致ByteBuf的自动释放逻辑异常。

排查&解决:

  • 升级Netty到4.1.x分支的最新稳定版(如4.1.100.Final及以上),这些版本修复了大量高版本Java的适配问题。

3. Codec编码逻辑中存在ByteBuf的额外引用

检查codec.encode(message)方法,确认生成的Unpooled ByteBuf没有被存入全局缓存、Message对象的成员变量等长生命周期容器中。如果ByteBuf被这些对象持有,即使writeAndFlush完成,也无法被GC回收。

排查&解决:

  • 在encode方法结束后打印ByteBuf的引用计数:System.out.println(buf.refCnt());
  • 在ChannelFuture完成的监听器中再次打印引用计数,确认是否降到0。如果未降到0,跟踪引用来源。

4. 启用Netty内存泄漏检测工具

Netty自带内存泄漏检测机制,开启后能精准定位泄漏点:

  • 添加JVM启动参数:
-Dio.netty.leakDetection.level=PARANOID

该参数会跟踪每个ByteBuf的分配和释放路径,一旦发现泄漏,会打印完整的堆栈信息,直接指向持有ByteBuf引用的代码位置。

内容的提问来源于stack exchange,提问作者Arshiya Kiani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 05:42:37