Netty设计思想之内存模型

Netty作为高性能网络库,其高性能主要归功于两个方面的设计:一方面是基于Reactor的事件驱动线程模型,全异步的数据处理提高的系统的吞吐量;另一方面,是精心设计和实现的内存模型,采用内存池,减少锁竞争,避免内存拷贝。

本文主要介绍下Netty的内存模型。

新的数据缓冲对象 - ByteBuf

为什么需要新的数据缓冲对象?不同于Java NIO的Bytebuffer,Netty设计的Bytebuf提供了更灵活的操作和更高级的功能,包括如下:

ByteBufByteBuffer的基本结构对比如下:

由上图可见,ByteBuf的读指针readerIndex和写指针writerIndex分离,使得操作更加直观,而不用像ByteBuffer一样分为读模式和写模式,模式切换还需要调用ByteBuffer.flip()操作进行切换,增加了编程的复杂度、易出错。

另外,ByteBuffer的容量初始化后是不可变的,而ByteBuf可以动态扩容。

零拷贝(zero copy)一般是指操作系统层面避免内核态到用户态的冗余数据拷贝,直接在内核态进行数据复制。Netty中的零拷贝主要是针对用户态中的部分场景尽量避免数据的冗余复制。比如组合多个缓冲可以使用CompositeByteBuf对象避免额外的内存拷贝。

池化是手动管理申请的内存,避免频繁的内存申请和释放,减少GC压力。虽然这和JVM的GC设计理念背道而驰,但是针对堆外内存的频繁申请和释放会影响性能,对于延迟敏感的网络应用程序来说是不可接受的。Netty设计了PooledByteBuf屏蔽了底层具体数据缓冲的实现(无论是Heap Buffer还是Direct Buffer),通过统一的接口(PooledByteBufferAllocator)进行内存的分配,并基于引用计数的机制回收对象。这种设计带来的负面影响是开发人员需要手动释放对象,但是对于其带来的收益,这点成本可以接受。

内存模型 - PoolThreadCache

Netty的内存池实现参考了jemelloc以及facebook的jemalloc实现。其主要思想如下:

我们先看下Netty内存管理的全局视图:

主要结构分为如下几个部分:

Powered by Jekyll and Theme by solid