内存检测原理使用的是PhantomReference技术,通过判断ByteBuf的refCount是否为0,判断是否存在内存泄漏。
检测原理
无论是池化的ByteBuf还是非池化的ByteBuf,BuyeBuf(不一定是该对象)对象在被gc回收之后,通过判断refCount是否为0来判断是否发生了内存泄漏。
netty支持下面四种级别,使用-Dio.netty.leakDetectionLevel=advanced
可以调节等级。
- 禁用(DISABLED) - 完全禁止泄露检测,省点消耗。
- 简单(SIMPLE) - 默认等级,告诉我们取样的1%的ByteBuf是否发生了泄露,但总共一次只打印一次,看不到就没有了。
- 高级(ADVANCED) - 告诉我们取样的1%的ByteBuf发生泄露的地方。每种类型的泄漏(创建的地方与访问路径一致)只打印一次。对性能有影响。
- 偏执(PARANOID) - 跟高级选项类似,但此选项检测所有ByteBuf,而不仅仅是取样的那1%。对性能有绝大的影响。
SIMPLE级别113才采样一个,但是每次新建一个buffer都会执行一次reportLeak进行内存泄漏检测。
检测出内存泄漏就说明有问题
对于非池化的ByteBuf不会有问题,但是池化的ByteBuf有问题。
- 因为非池化的ByteBuf即使refCount没减为0,但是gc机制也会回收掉对应内存,所以不会造成大问题。但是如果程序及时释放不使用的内存肯定更好,以便该内存能被及时的会回收掉。
- 虽然ByteBuf可以被gc回收,但是ByteBuf内部引用的数组内存还是被池数据结构引用不能被释放,造成内存不能释放给到池子,最终造成池子里无内存可分配。
如何释放ByteBuf
ReferenceCountUtil.release(msg);
一个内存泄漏案例
设备上行的消息大小超过限制后就直接关闭了channel,而没有释放内存。
OOM信息?内存检测信息?
程序一定要显示的释放内存
以非池化的BuyeBuf举例。对于堆内内存,netty会把数组对象置为空使内存可以快速的被GC会收掉。对于直接内存,ntty会直接通过cleaner释放掉内存,而不用等GC机制释放掉(GC释放直接内存不是很靠谱)。