概述
1. 概念
所谓零拷贝,就是在操作数据是,不需要将数据buffer从一个内存区域拷贝到另一个内存区域。因此减少内存的拷贝,CPU的效率得到提升。
在OS层面上的零拷贝通常指避免在用户态(User-space)与内核态(Kernel-space)之间来回拷贝数据。例如Linux提供的mmap系统调用,它可以将一段用户内存映射到内核空间,当映射成功后,用户对这段内存区域的修改可以直接放映到内核空间;同样的,内核空间对这段区域的修改也直接反映到用户空间。正因为这样的映射关系,就不需要在用户态与内核态之间拷贝数据,提高了数据传输的效率。
Netty中零拷贝与上面所提的零拷贝不太一样。Netty的零拷贝完全是在用户态的,更多的是偏向于优化数据操作的概念。Netty的零拷贝体现在如下几个方面:
- Netty提供了CompositeByteBuf类,它可以将多个ByteBuf合并为一个逻辑上的ByteBuf,避免了各个ByteBuf之间的拷贝
- 通过wrap操作,可以将byte[]数组、BytebBuf、ByteBuffer等包装成一个Netty ByteBuf对象,避免了拷贝操作
- ByteBuf支持slice操作,因此可以将ByteBuf分解为多个共享同一个存储区域ByteBuf,避免了内存的拷贝
- 通过FileRegion包装的FileChannel.tranferTo实现文件传输,可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝的问题
2. 堆外内存
使用堆外内存的原因
- 改善垃圾回收停顿
- 在某些场景下可以提升程序I/O操纵的性能。少去了将数据从堆内内存拷贝到堆外内存的步骤
什么情况下使用堆外内存
- 堆外内存适用于生命周期中等或较长的对象。( 如果是生命周期较短的对象,在YGC的时候就被回收了,就不存在大内存且生命周期较长的对象在FGC对应用造成的性能影响 )。
- 直接的文件拷贝操作,或者I/O操作。直接使用堆外内存就能少去内存从用户内存拷贝到系统内存的操作,因为I/O操作是系统内核内存和设备间的通信,而不是通过程序直接和外设通信的。
- 同时,还可以使用“池+堆外内存”的组合方式,来对生命周期较短,但涉及到I/O操作的对象进行堆外内存的再使用。( Netty中就使用了该方式 )
堆外内存 VS 内存池
- 内存池:主要用于两类对象:①生命周期较短,且结构简单的对象,在内存池中重复利用这些对象能增加CPU缓存的命中率,从而提高性能;②加载含有大量重复对象的大片数据,此时使用内存池能减少垃圾回收的时间。
- 堆外内存:它和内存池一样,也能缩短垃圾回收时间,但是它适用的对象和内存池完全相反。内存池往往适用于生命期较短的可变对象,而生命期中等或较长的对象,正是堆外内存要解决的。
堆外内存的特点
- 对于大内存有良好的伸缩性
- 对垃圾回收停顿的改善可以明显感觉到
- 在进程间可以共享,减少虚拟机间的复制
堆外内存的一些问题
- 堆外内存回收问题,以及堆外内存的泄漏问题
- 堆外内存的数据结构问题:堆外内存最大的问题就是你的数据结构变得不那么直观,如果数据结构比较复杂,就要对它进行串行化(serialization),而串行化本身也会影响性能。另一个问题是由于你可以使用更大的内存,你可能开始担心虚拟内存(即硬盘)的速度对你的影响了。
文档
- 深入剖析Linux IO原理和几种零拷贝机制的实现
最后
以上就是时尚白开水为你收集整理的Netty源码解析 - 零拷贝的全部内容,希望文章能够帮你解决Netty源码解析 - 零拷贝所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复