Linux、Java、Netty的零拷贝

零拷贝的概念

在不同场景下,零拷贝的概念是不同的。
在操作系统层面,零拷贝是指在用户态和内核态的拷贝次数为0。
在Java中有一些类是支持零拷贝的(如果操作系统支持),对应的是操作系统的零拷贝。
在Netty中,指的只是在用户层面(java层面)的拷贝次数为0。

零拷贝如何实现

操作系统层面

在操作系统的层面实现零拷贝依赖于操作系统的命令,主要有两种方案:1.sendfile命令。2.mmap命令。
这里注意:在操作系统层面的零拷贝是有一定场景约束的,必须限制的把文件发送到socket或者从socket读取到file,中间是不能对文件进行修改的。对应在sendfile或者mmap的命令上也可以提现出来,这两个命令都含有file_fd(文件描述符)相关的参数。对应到Java nio也可以体现,就是FileChannel.transferToFileChannel.transferFrom都含有File相关参数。Java nio中MappedByteBuffer也是对应的零拷贝的内存,这个类也是对应的一个File。

Netty层面

在Netty层面,零拷贝就是减少Java层面内存的拷贝。比如:1.使用直接内存,就减少了直接内存与堆内存之间的拷贝。2.当多个ByteBuf组合成一个Bytebuf时,使用CompositeByteBuf组合而不是复制数据。3.与文件相关操作时使用Java nio的FileChannel.transferTo。
Netty的直接内存是什么?
比如我们使用 ByteBuf byteBuf = Unpooled.directBuffer(10);申请一个直接内存。
Netty使用Unsafe.allocateMemory申请内存,返回内存的地址,用Unsafe.allocateMemory返回的地址和长度等包装成DirectByteBuffer对象。这个DirectByteBuffer是Java nio包类的类。再使用DirectByteBuffer对象来构造ByteBuf对象。

总结

操作系统层面的零拷贝有场景限制,就是文件的发送与接收,中间不能修改数据。
如果我们从socket接收数据,进行计算以后发送出去,这个过程不涉及File。Netty只是在我们见的到的Java层面减少了数据的复制。

这里还有一个问题:Netty里使用的直接内存到底是什么?在操作系统层面内存是分内核态和用户态的,那Netty里的直接内存是内核态呢还是用户态?数据从客户端发送过来,存储在网卡中,通过DMA read到内核缓冲区,Netty使用的直接内存是内核缓冲区里的数据吗?还是需要一次内存拷贝到用户态。

首先,Netty里的直接内存是Java nio的DirectByteBuffer
从操作系统上讲,内存分两部分:内核态(由操作系统内核操作,读写磁盘,读写网络都是由这负责);用户态(我们的进程使用的内存。)
jvm启动的时候会在用户态申请一块内存,申请的这块内存中有一部分会被称为堆,一般我我们申请的对象就会放在这个堆上,堆上的对象是受gc管理的。那么除了堆内的内存,其他的内存都被称为对外内存。在堆外内存中如果我们是通过Java的DirectByteBuffer申请的,那么这块内存其实也是间接受gc管理的,而如果我们通过jni直接调用c函数申请一块堆外内存,那么这块内存就只能我们自己手动管理了。
当我们在Java中发起一个文件读操作会发生什么呢?首先内核会将数据从磁盘读到内核态内存,再从内核态内存拷贝到用户态的堆外内存(这部分是jvm实现),然后再将数据从堆外拷贝到堆内。拷贝到堆内其实就是我们在Java中自己手动申请的byte数组中。
而使用DirectByteBuffer就减少了从堆外内存到堆内内存的拷贝过程。

参考

第九周–零拷贝(高性能IO的关键之一)

Netty中的零拷贝

共享内存mmap介绍

Java直接内存是属于内核态还是用户态?

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值