相关参数
-Dio.netty.noResourceLeakDetection=false # 就版本是否禁用泄漏检测, 默认不禁用, 已过时, 新版本建议用检测级别配置设置
-Dio.netty.leakDetectionLevel=PARANOID #旧版本配置, paranoid级别检测
-Dio.netty.leakDetection.level=advanced #新版本配置, advanced级别检测
-Dio.netty.leakDetection.targetRecords=4 #发生泄漏目标记录数, 默认4个, 超出会丢弃, 如果有提示丢弃的存在, 可以适当调大
-Dio.netty.leakDetection.samplingInterval=128 #检测采样率设置, 默认128次采样一次
检测级别:
级别 | 描述 |
---|---|
DISABLED | 禁止泄漏检测。只有详尽测试之后才应该设置这个值。 |
SIMPLE | 使用1%的默认采样率检测, 默认级别。适合大部分场景。 |
ADVANCED | 使用默认采样率, 但是有泄漏出现, 会打印详细信息 |
PARANOID | 偏执模式, 全量采样, 如果有泄漏出现, 会打印详细信息。 |
测试代码:
@Test
public void test2() throws Exception {
PooledByteBufAllocator allocator = new PooledByteBufAllocator(true);
IntStream.range(0, 128).forEach(i->{
ByteBuf bf = allocator.directBuffer(100);
// bf.release();
// bf = null;
System.gc();
});
TimeUnit.SECONDS.sleep(11);
}
junit5+embeddedchannel 检测handler内存泄漏问题
添加jvm参数 -Dio.netty.leakDetection.level=paranoid
//测试的TestServerHandler代码
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf bf = (ByteBuf)msg;
System.out.println(ci+" channel read msg: "+bf.toString(CharsetUtil.UTF_8));
//不加这一行将会产生内存泄漏
// ReferenceCountUtil.safeRelease(bf);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println(ci+" channel read completed!");
ctx.writeAndFlush(Unpooled.copiedBuffer((ci+
" finished recieved your message!").getBytes(CharsetUtil.UTF_8)));
//因为netty内存泄漏检测是通过gc触发的, 所以这里要加个主动gc的代码
System.gc();
System.out.println("gc finished.");
}
//单元测试代码
private void testServerChannelHandler(){
EmbeddedChannel ec = new EmbeddedChannel();
ChannelPipeline pipeline = ec.pipeline();
pipeline.addLast(new TestServerHandler()).addLast(new LoggingHandler(LogLevel.INFO));
//模拟分配的buffer数据
ByteBuf buffer = ec.config().getAllocator().buffer();
buffer.writeBytes("test".getBytes(StandardCharsets.UTF_8));
//将测试数据写入channel
ec.writeInbound(buffer);
ec.finishAndReleaseAll();
}
// @Test
//用的4.1.75版本, 这里总是第三次才能打印出leak信息, 不知道为什么, 后面有时间研究下源码, 看看为什么会这样。
@RepeatedTest(3)
public void test() throws Exception {
testServerChannelHandler();
TimeUnit.SECONDS.sleep(1);
}
测试报告中会提示发生泄漏的地方
ERROR io.netty.util.ResourceLeakDetector - LEAK: ByteBuf.release() was not called before it’s garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
#1:
io.netty.buffer.AdvancedLeakAwareByteBuf.toString(AdvancedLeakAwareByteBuf.java:743)
com.example.testcases.netty.server.handler.TestServerHandler.channelRead(TestServerHandler.java:22)