引言

Netty 4.0 之后,netty中某些对象的生命周期由它们的引用计数管理,如ByteBuf是利用引用计数来提高分配和释放性能的最著名类型.

引用计数

—1—引用计数对象的初始引用计数为 1。
—2—当释放引用计数对象时,它的引用计数减 1。

一般法则是,最后访问引用计数对象的一方也负责销毁该引用计数对象。具体来说:
如果 [发送] 组件应该将引用计数对象传递给另一个 [接收] 组件,发送组件通常不需要销毁它,而是将决定推迟到接收组件。
如果一个组件使用了一个引用计数的对象并且知道没有其他人会再访问它(即,不传递对另一个组件的引用),则该组件应该销毁它。

—3—如果引用计数达到 0,则引用计数对象被释放或返回到它来自的对象池,尝试访问引用计数为 0 的引用计数对象将触发IllegalReferenceCountException。
—4—当对象还没有被销毁之前,引用计数也可以通过retain()操作增加。

Derived buffers

—1—ByteBuf.duplicate()、ByteBuf.slice()及ByteBuf.order(ByteOrder)创建一个共享父缓冲区内存区域的派生缓冲区。派生缓冲区没有自己的引用计数,但共享父缓冲区的引用计数。
—2—相反,ByteBuf.copy()和ByteBuf.readBytes(int)不是派生缓冲区。返回ByteBuf的已分配,需要释放。需要注意的是,父缓冲区及其派生缓冲区共享相同的引用计数,并且创建派生缓冲区时引用计数不会增加。因此,如果您要将派生缓冲区传递给应用程序的其他组件,则必须先调用retain()它。

ByteBufHolder interface

可使用ByteBufHolder 持有 ByteBuf,例如DatagramPacket、HttpContent和WebSocketframe .这些类都继承自ByteBufHolder。和Derived buffers一样,ByteBufHolder持有者共享其包含的缓冲区的引用计数。

ChannelHandler 的引用计数

Inbound messages(入站消息)

—1—当事件循环将数据读入ByteBuf并触发channelRead()事件时,ChannelHandler相应管道中的 负责释放缓冲区。因此,使用接收到的数据的处理程序应该release()在其channelRead()处理程序方法中调用数据。
—2—如果处理程序将缓冲区(或任何引用计数对象)传递给下一个处理程序,则无需释放它。
—3—可以直接使用ReferenceCountUtil.release(),或考虑扩展SimpleChannelHandlerwhich 对所有消息调用ReferenceCountUtil.release(msg)。

Outbound messages(出站消息)

与入站消息不同,出站消息是由自己的应用程序创建的,Netty 负责在将它们写入网络后释放这些消息。

特别注意encoders之后正确释放。

Mpsc Queue

Mpsc 的全称是 Multi Producer Single Consumer,多生产者单消费者。Mpsc Queue 可以保证多个生产者同时访问队列是线程安全的,而且同一时刻只允许一个消费者从队列中读取数据。Netty Reactor 线程中任务队列 taskQueue 必须满足多个生产者可以同时提交任务,所以 JCTools 提供的 Mpsc Queue 非常适合 Netty Reactor 线程模型。

MpscArrayQueue

—1—通过大量填充 long 类型变量解决伪共享问题。
—2—环形数组的容量设置为 2 的次幂,可以通过位运算快速定位到数组对应下标。
—3—入队 offer() 操作中 producerLimit 的巧妙设计,大幅度减少了主动获取消费者索引 consumerIndex 的次数,性能提升显著。
—4—入队和出队操作中都大量使用了 UNSAFE 系列方法,针对生产者和消费者的场景不同,使用的 UNSAFE 方法也是不一样的。Jctools 在底层操作的运用上也是有的放矢,把性能发挥到极致。


ciwi
1 声望0 粉丝

引用和评论

0 条评论