背景、netty抛出完整的error信息如下:
2018-02-08 14:30:43.098 [nioEventLoopGroup-5-1] ERROR io.netty.util.ResourceLeakDetector:176 - LEAK: ByteBuf.release() was not called before it's garbage-collected. Enable advanced leak reporting to find out where the leak occurred. To enable advanced leak reporting, specify the JVM option '-Dio.netty.leakDetection.level=advanced' or call ResourceLeakDetector.setLevel() See http://netty.io/wiki/reference-counted-objects.html for more information.
一、结论很直观:内存泄露了
再读读提示:获取更多的信息有两种方法
1. 增加启动jvm参数-Dio.netty.leakDetection.level=advanced
java -jar -Dio.netty.leakDetection.level=advanced your-server.jar
或者
java -jar -Dio.netty.leakDetectionLevel=ADVANCED your-server.jar
2. 在程序启动时增加相关日志信息
...省略代码...
try { ServerBootstrap sbs = new ServerBootstrap().group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class).handler(new LoggingHandler(LogLevel.INFO)) .localAddress(new InetSocketAddress(port)) .childHandler(new ChannelInitializer<SocketChannel>() { protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new IdleStateHandler(10, 0, 0, TimeUnit.SECONDS)); ch.pipeline().addLast(idleStateTrigger); ch.pipeline().addLast("decoder", new MessageDecoder()); ch.pipeline().addLast("encoder", new MessageEncoder()); ch.pipeline().addLast(serverHandler); }; }).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.ADVANCED);
ChannelFuture future = sbs.bind(port).sync();
...省略代码...
二、这两种方式都能跟踪到内存泄露时的更多的抛出信息
Recent access records: 2 #2: io.netty.buffer.AdvancedLeakAwareByteBuf.readBytes(AdvancedLeakAwareByteBuf.java:498) io.netty.buffer.ByteBufInputStream.read(ByteBufInputStream.java:179) com.esotericsoftware.kryo.io.Input.fill(Input.java:164) com.esotericsoftware.kryo.io.Input.require(Input.java:196) com.esotericsoftware.kryo.io.Input.readVarInt(Input.java:373) com.esotericsoftware.kryo.util.DefaultClassResolver.readClass(DefaultClassResolver.java:127) com.esotericsoftware.kryo.Kryo.readClass(Kryo.java:693) com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:804) com.your.package.base.serialize.KryoSerializer.deserialize(KryoSerializer.java:54) com.your.package.base.link.MessageDecoder.decode(MessageDecoder.java:53) io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(...)
三、解决问题
分析日志,建议从自己的代码入手,然后将造成内存泄露的ByteBuf手动释放。
ReferenceCountUtil.release(byteBuf);