Netty之引用计数器

转载:http://calvin1978.blogcn.com/articles/netty-leak.html

引用计数器的必要性

  在内存池的场景中,ByteBuf不再使用时需要主动归还给内存池;

引用计数器相关知识

  1. ByteBuf被创建时,引用计数的初始值为1;
  2. 调用release(),计数器减1,当计数器等于零时, deallocate()被调用,回收资源;
  3. 调用release()或者retain()方法时,如果引用计数器为负数,直接抛出IllegalReferenceCountException异常;
  4. 计数器基于AtomicIntegerFieldUpdater实现。 不直接用AtomicInteger的原因是ByteBuf对象很多,如果都把int包一层AtomicInteger花销较大,而AtomicIntegerFieldUpdater只需要一个全局的静态变量。

Release原则

  在C/C++中,malloc和free是成对出现的,而在Netty里,因为Handler链的存在,ByteBuf经常要传递到下一个Hanlder,所以Release规则变成了:由最后使用ByteBuf的Handler负责释放。 另外,需要注意的是如果在Handler中出现异常,ByteBuf没有成功传递到下一个Hanlder,需要有当前Handler进行释放。

接受消息

ByteBuf分配:在AbstractNioByteChannel.NioByteUnsafe.read() 处创建ByteBuf(引用计数为1),调用 pipeline.fireChannelRead(byteBuf) 送入Handler链。
Handler链处理:
  根据谁最后使用谁负责释放的原则,每个Handler对消息可能有三种处理方式:

  1. 对原消息不做处理,调用 ctx.fireChannelRead(msg)把原消息往下传,那不用做什么释放;
  2. 将原消息转化为新的消息并调用 ctx.fireChannelRead(newMsg)往下传,那必须把原消息release掉;
  3. 如果已经不再调用ctx.fireChannelRead(msg)传递任何消息,那更要把原消息release掉;
发送消息

ByteBuf分配: 待发送消息由应用所创建,并调用 ctx.writeAndFlush(msg) 进入Handler链。
Handler链处理: 在每个Handler中的处理类似InBound Message,最后消息会来到HeadHandler,再经过一轮复杂的调用,在flush完成后Netty会将其release掉。

异常处理时的释放

大于0的判断: 在多层异常处理机制中,有些异常处理的地方不一定准确知道ByteBuf之前释放了没有,可以在释放前加上引用计数大于0的判断避免抛出异常;

彻底释放: 有时候不清楚ByteBuf被引用了多少次,但又必须在此进行彻底的释放,可以循环调用reelase()直到返回true。

类关系

这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值