吃透Netty源码系列五十之ByteBuf内存泄漏简单分析

最容易内存泄漏的例子

客户端代码

写个处理器,里面就加这段,就给服务器发送1亿条1
在这里插入图片描述

服务端代码

写个处理器继承ChannelInboundHandlerAdapter,就获取消息对象,转成字节缓冲区,打印内存地址和内容。
在这里插入图片描述

堆内内存溢出

虚拟机参数设置

为了让堆内内存快速溢出,我加了虚拟机参数:

-Xmx10m //堆内最大10M
-XX:MaxDirectMemorySize=800M //堆外800M
-Dio.netty.allocator.maxOrder=4 //让缓存区变小,可以让块变小,可以开启缓存
-XX:+HeapDumpOnOutOfMemoryError //监控堆内溢出了
-XX:HeapDumpPath=D:\gc.dump //把溢出信息保存到文件里

这里要注意,为了快速看到堆内存溢出,我把堆最大内存设置为10M,但是这样netty默认的设置就达不到开启缓存的要求,就不池化了,所以我设置io.netty.allocator.maxOrder=4 ,让块内存变小,可以开启缓存池化,如果不开启池化了,直接用UnpooledUnsafeDirectByteBuf,我们希望使用默认的PooledUnsafeDirectByteBuf堆内内存溢出,所以要开启缓存,因为netty现在默认是用PooledUnsafeDirectByteBuf来做IO缓冲区的。至于为什么要这么设置,可以去PooledByteBufAllocator的静态代码块里看,里面都有,自己调试下好了:
在这里插入图片描述
在这里插入图片描述

运行服务端

还没开启客户端

还没客户端的时候:
在这里插入图片描述

开启客户端

内存地址一直在变,说明没有池化复用。
在这里插入图片描述

visualvm看内存使用情况

内存方面也开始不停的GC
在这里插入图片描述

visualvm看内存对象数量

内存里这几个对象特别多,一个是缓存分配里的子页内存,其他两个是回收句柄和缓冲区:
在这里插入图片描述

visualvm看GC情况

3分钟左右的GC情况,两种GC都很多了:

在这里插入图片描述

堆内内存溢出了

过了一会儿堆内内存溢出了:
在这里插入图片描述

visualvm看dump文件

然后我们看dump文件:
在这里插入图片描述
很多都是PoolSubPage,说明创建了好多小缓冲区,没有复用。

为什么会出现这种呢,不是说netty会自动释放么,其实有自动释放的,好多地方,比如如果你用SimpleChannelInboundHandler的话,就会自动释放,其实是封装了一层而已:
在这里插入图片描述

最简单解决方法-自己释放

如果我们自己释放呢:
在这里插入图片描述
首先缓冲区复用了:
在这里插入图片描述

内存比较稳:
在这里插入图片描述
GC也还行,没有full gc
在这里插入图片描述
也是3分钟左右,这次的对象个数很稳定:
在这里插入图片描述
内存也一直稳:
在这里插入图片描述

大多数情况可能使用ChannelInboundHandlerAdapter传进来的缓冲区,其实这个是IO的读缓冲区,如果后面不用了,要释放,不然就导致泄漏啦。当然系统也有好多处理器会帮你释放这个,后面我会讲下哪些情况,系统会帮你释放。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值