linux支持的零拷贝类型以及java对应的支持

在之前整理的零拷贝文章基础上

https://blog.csdn.net/zlpzlpzyd/article/details/135321197

https://blog.csdn.net/zlpzlpzyd/article/details/135317834

得出如下

因为开发的程序很多运行在 linux 操作系统上,所以用 linux 进行讲解

linux 调用方式

dma复制次数

cpu复制次数

用户态切换次数

内核态切换次数

系统调用次数

对应 java 实现

备注

传统io(read+write)

2

2

2

2

2

InputStream 和OutputStream 的实现类

Writer 和 Reader 的实现类

数据需要通过 cpu 从内核态复制到用户态

mmap+write

2

1

2

2

2

MappedByteBuffer

采用虚拟内存,多个虚拟内存可以指向同一个物理地址。利用这个特性,可以把内核空间和用户空间的虚拟地址映射到同一个物理地址,这样在I/O操作时就不需要来回复制。将内核中的读缓冲区与用户空间的缓冲区进行映射,所有的IO都在内核中完成。
通过类似指针的方式操作 page cache,cpu 的复制在内核执行,不需要复制到应用程序。

sendfile

2

1

1

1

1

FileChannel 的 transferFrom() 和 transferTo()

替代前面的 read() 和 write() 这两个系统调用

sendfile+DMA scatter/gather

2

0

1

1

1

将 cpu 的复制操作交给网卡去做,需要网卡支持并且提供对应的驱动程序。

direct io

2 0 1 1 1

在 java 10 中提供了 api

splice

2

0

1

1

1

splice函数用于在两个文件描述符之间移动数据,而不需要数据在内核空间和用户空间中来回拷贝。

使用splice函数时输入和输出至少有一个是管道文件描述符。

只适用于将数据从文件拷贝到套接字上,限定了它的使用范围。

tee

2

0

1

1

1

在两个管道文件描述符之间复制数据,并且它是直接复制,不会将数据读出。

如上述表格,在传统 io 的基础上,mmap 方式少了一次 cpu 复制,sendfile 相比  mmap 少了1次用户态切换,1次内核态切换,系统调用少了1次,sendfile+DMA scatter/gather 在单纯的 sendfile 调用基础上少了1次cpu复制,后面的 direct io、splice、tee 在资源消耗上类似。

由此可见,对于 io 的问题无论怎么优化,dma复制的次数、用户态和内核态切换的次数、调用操作系统 api 的次数都是无法避免的,因为开发的程序运行在用户态,调用操作系统 api 就要进行用户态和内核态切换。

针对 splice 功能在 openjdk 的 bug 里提出了,但是还没解决

https://bugs.openjdk.org/browse/JDK-8303934

tee 的功能还不支持

参考链接

https://www.toutiao.com/article/7100795589604033059

https://juejin.cn/post/6862877857258045453

https://www.jianshu.com/p/fad3339e3448

https://zhuanlan.zhihu.com/p/78869158

https://zhuanlan.zhihu.com/p/592397046

https://zhuanlan.zhihu.com/p/573893175

https://zhuanlan.zhihu.com/p/608726921

你可能感兴趣的:(操作系统,jvm,java,linux,java,jvm,nio,网络)