最容易内存泄漏的例子
客户端代码
写个处理器,里面就加这段,就给服务器发送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
的读缓冲区,如果后面不用了,要释放,不然就导致泄漏啦。当然系统也有好多处理器会帮你释放这个,后面我会讲下哪些情况,系统会帮你释放。
好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。