Netty源码解析 - 零拷贝

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),而串行化本身也会影响性能。另一个问题是由于你可以使用更大的内存,你可能开始担心虚拟内存(即硬盘)的速度对你的影响了。

文档

  1. 深入剖析Linux IO原理和几种零拷贝机制的实现
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值