NIO中的非直接缓冲区、直接缓冲区、内存映射、零拷贝

先说明几个概念:

  1. 零拷贝:此处的零拷贝指的是没有CPU拷贝,现在不少人觉得linux的senfile才是零拷贝,这不重要,只要把各种技术点的实现细节整明白就好了
  2. DMA拷贝:内存与IO设备之间的拷贝,不使用cpu,而是使用主板上独立的芯片完成拷贝操作  eg:磁盘<-->内存、网卡<-->内存

 

非直接缓冲区(ByteBuffer)

  1. 在jvm中开辟数据空间(用户空间);
  2. 每次的io操作都会有内核空间缓存和jvm缓存之间的copy操作
  3. 以网络IO往外读为例:JVM用户内存 通过CPU拷贝->内核缓冲buffer  通过DMA拷贝->网络协议通道中

直接缓冲区DirectByteBuffer(零拷贝)

  1. 在jvm越过jvm堆直接开辟内核空间(address= unsafe.allocateMemory(size) 开辟一个size大小的空间返回该空间的首地址)
  2. jvm中只存有数据的引用地址,为了内核安全该地址也不是真正的内核空间地址,而是会有一个中间的内存地址映射表,完成寻址
  3. 以网络IO往外读为例:内核区缓冲bufferDMA拷贝->网络协议通道中
  4. 场景:将创建的DirectByteBuffer中添加的内容写出到文件或网络

mmap内存映射MappedByteBuffer (零拷贝)【mmap这块查阅了不少资料,结果都不尽相同,一下为个人理解】

  1. 直接将一个磁盘文件地址作为一个虚拟内存地址,操作这块地址时若发现未在物理内存中,则会触发缺页中断,将其加载至内核的物理内存中操作,二者会建立映射关系,操作物理内存的动作也会反映到虚拟内存地址
  2. MappedByteBuffer的实现类之所以是DirectByteBuffer,是为了使用DirectByteBuffer对堆外内存的操作函数
  3. 多用于对大文件的直接操作
  4. 场景:直接修改磁盘文件内容

说明一个概念:jvm若要把自身的数据传送到外界时(比如IO操作),数据要先送往内核,然后由内核在内核空间中完成相应IO操作。
理论上内核是能访问到所有的内存空间的,为什么不直接访问jvm堆进行操作呢?
答:因为JVM进行GC时SWT只是停止所有jvm的操作,而不能停止内核中的操作,若内核正在访问时GC进行垃圾回收,将这块数据进行了复制移动,就会出问题

DirectByteBuffer的堆外空间是如何实现GC管理的呢:他有一个属性sun.misc.Cleaner类型的,该种类型的属性在进行垃圾回收时会触发cleaner.clean(),其中的逻辑是执行cleaner.thunk.run(),thunk是个runable的类型属性,而directByteBuffer.cleaner初始化的thunk中的run方法中的逻辑有一句unsafe.freeMemory(address);实现了堆外内存的回收【回收方式注意和netty中的引用计数主动释放区分】

IO中的管道与管道直连的零拷贝:

  1. linux环境下文件io中的fileChannel.transferTo方法,底层调用的linux中独有的指令sendfile
  2. 以传送文件为例:磁盘DMA拷贝->内核缓冲bufferDMA拷贝->网络协议通道中(如果不是零拷贝过程:磁盘DMA拷贝->内核内存cpu拷贝->jvm内存cpu拷贝->内核缓冲bufferDMA拷贝->网络协议通道中)
  3. 场景:将两个通道直接连接传送数据,例如将文件发送到网络io,将网络io写入文件(channel.transferTo/transferFrom在linux的系统底层调用的就是sendfile指令)

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值