背景、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);