零拷贝
2021-11-03 17:45:02 23 举报
零拷贝相关的思路流程图
作者其他创作
大纲/内容
用户态
socket缓冲区
mmap一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。1. MappedByteBuffer 使用虚拟内存,因此分配(map)的内存大小不受JVM的-Xmx参数限制,但是也是有大小限制的(通过源码可知最大为 Integer.MAX_VALUE,2G)。2. 一次 map 的大小最好限制在 1.5G 左右3. 当文件超出限制时,可以通过position参数重新map文件后面的内容。4. 使用 MappedByteBuffer 操作大文件比 IO 流要快(对于小文件,内存映射文件反而会导致碎片空间的浪费,因为内存映射总是要对齐页边界,最小单位是 4 KiB,一个 5 KiB 的文件将会映射占用 8 KiB 内存,也就会浪费 3 KiB 内存。)5. 加载文件的内存在 Java 的堆内存之外,允许两个不同进程访问文件。6. 不要经常调用MappedByteBuffer.force()方法,这个方法强制操作系统将内存中的内容写入硬盘,所以如果你在每次写内存映射文件后都调用force()方法,你就不能真正从内存映射文件中获益,而是跟disk IO差不多。
CPU
用户空间
磁盘
4. 将数据发送客户端
内核态
内核缓冲区
网卡
1. 读取磁盘到缓冲区
零拷贝 : Sendfile方式
内核缓冲区到socket缓冲区,只会将一些 offset 和 length 信息拷入 socket 缓冲区,几乎无消耗
2. 将缓冲区读到堆内存中
3. 将数据发送客户端
零拷贝 : mmap+write方式
Sendfile 系统调用的引入,不仅减少了数据复制,还减少了上下文切换的次数。 1. java 调用 transferTo 方法后,要从 java 程序的用户态切换至内核态,使用 DMA将数据读入内核缓冲区,不会使用 cpu2. 数据从内核缓冲区传输到 socket 缓冲区,cpu 会参与拷贝3. 最后使用 DMA 将 socket 缓冲区的数据写入网卡,不会使用 cpu整个过程仅只发生了一次用户态与内核态的切换,数据拷贝了 2 次。
传统层面的读写文件
2. 将用户内存映射到内核内存
零拷贝:https://mp.weixin.qq.com/s/VfOOI6v9tw3jRip-a4ci2Q
3. 操作写入缓冲区
1. java 本身并不具备 IO 读写能力,因此 read 方法调用后,要从 java 程序的用户态切换至内核态,去调用操作系统(Kernel)的读能力,将数据读入内核缓冲区。这期间用户线程阻塞,操作系统使用 DMA(Direct Memory Access)来实现文件读,其间也不会使用 cpu。2. 从内核态切换回用户态,将数据从内核缓冲区读入用户缓冲区(即 byte[] buf),这期间 cpu 会参与拷贝,无法利用 DMA3. 调用 write 方法,这时将数据从用户缓冲区(byte[] buf)写入 socket 缓冲区,cpu 会参与拷贝4. 接下来要向网卡写数据,这项能力 java 又不具备,因此又得从用户态切换至内核态,调用操作系统的写能力,使用 DMA 将 socket 缓冲区的数据写入网卡,不会使用 cpu
0 条评论
下一页
为你推荐
查看更多