关于netty:Netty源码解析-零拷贝机制与PoolArena
本文分享Netty中零拷贝机制与PoolArena的实现原理。 源码剖析基于Netty 4.1 Netty中的零拷贝首先看一下Netty中实现零拷贝的机制 1.文件传输类DefaultFileRegion#transferTo,调用FileChannel#transferTo,间接将文件缓冲区的数据发送到指标Channel,缩小用户缓冲区的拷贝(通过linux的sendfile函数)。 应用read 和 write DMA拷贝 拷贝,切换到用户态 拷贝,切换到内核态硬盘 --------> 内核缓冲区(内核态) ----------------> 用户缓冲区(用户态) ----------------> socket缓冲区 应用sendfile DMA拷贝 拷贝硬盘 --------> 内核缓冲区(内核态) ----> socket缓冲区 缩小用户态,内核态切换,以及数据拷贝 可参考: 操作系统和Web服务器那点事儿 2.Unpooled#wrappedBuffer办法,将byte数据,(jvm)ByteBuffer转换为ByteBufCompositeByteBuf#addComponents办法,合并ByteBufByteBuf#slice办法,提取ByteBuf中局部数据片段这些办法都是基于对象援用的操作,并没有内存拷贝 3.应用堆外内存(jvm)ByteBuffer对Socket读写。如果应用JVM的堆内存进行Socket读写,JVM会将堆内存拷贝一份到间接内存中,而后才写入Socket中。应用堆外内存能够防止该拷贝操作。留神,这里从内核缓冲区拷贝到用户缓冲区的操作并不能省略,毕竟咱们须要对数据进行操作,所以还是要拷贝到用户态的。可参考: 知乎--Java NIO中,对于DirectBuffer,HeapBuffer的疑难 接口关系ByteBufAllocator,内存分配器,负责为ByteBuf分配内存, 线程平安。PooledByteBufAllocator,默认的ByteBufAllocator,事后从操作系统中申请一大块内存,在该内存上分配内存给ByteBuf,能够进步性能和减小内存碎片。UnPooledByteBufAllocator,非池化内存分配器,每次都从操作系统中申请内存。 RecvByteBufAllocator,接管内存分配器,为Channel读入的IO数据调配一块大小正当的buffer空间。具体性能交由外部接口Handle定义。它次要是针对Channel读入场景增加一些操作,如guess,incMessagesRead,lastBytesRead等等。 ByteBuf,代表一个内存块,提供程序拜访和随机拜访,是一个或多个Byte数组或NIO Buffers的形象视图。ByteBuf次要能够分为堆外内存DirectByteBuf和堆内存HeapByteBuf。Netty4中ByteBuf调整为抽象类,从而晋升吞吐量。 上面只关注PooledByteBufAllocator,它是Netty中默认的内存调配策略(unsafe反对),也是了解Netty内存机制的难点。 内存调配后面文章《ChannelPipeline与Read,Write,Connect事件处理》中解析的read事件处理,NioByteUnsafe#read public final void read() { ... final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle(); allocHandle.reset(config); ByteBuf byteBuf = null; boolean close = false; ... byteBuf = allocHandle.allocate(allocator); allocHandle.lastBytesRead(doReadBytes(byteBuf)); ...}recvBufAllocHandle办法返回AdaptiveRecvByteBufAllocator.HandleImpl。(AdaptiveRecvByteBufAllocator,PooledByteBufAllocator都在DefaultChannelConfig中初始化) ...