美文网首页
NIO零拷贝

NIO零拷贝

作者: 黑铁大魔王 | 来源:发表于2020-05-13 19:25 被阅读0次

    先来偷个图,然后扶好小板凳,别摔着了。
    这是传统IO的文件操作


    传统IO传输文件.png

    假设有以下场景,浏览器请求磁盘上的文件a.txt,那么会大致经历以下几个步骤:

    1. 从磁盘读文件
    2. 把文件传输给浏览器

    好,大致步骤完毕,那么接下来是详细步骤

    1. 从磁盘读文件属于内核操作,由于jvm运行在用户空间,那么当jvm接收到从磁盘读取文件的事件时,需要调用系统函数通过内核来读取a.txt,并且将a.txt缓存在内核空间的缓冲区
    2. 内核将a.txt读取到内核缓冲区后,jvm将其a.txt从内核缓冲区copy到用户空间缓冲区
    3. jvm copy完成之后,将数据发送到浏览器,那么需要通过网卡,网卡属于外设,操作外设需要内核操作,于是:
      3.1 jvm将数据copy到内核缓冲区
      3.2 内核将数据写入网卡
      3.3 内核返回jvm
      3.4 jvm操作结束

    以上操作就是传统io的文件下载操作,可以发现,整个过程中经历了4次copy操作,分别是:
    1. 磁盘 -> 内核
    2. 内核 -> 用户
    3. 用户 -> 内核
    4. 内核 -> 网卡
    这种操作有个显而易见的缺点,从内核到用户从用户到内核,这2步似乎是多余的,为何不直接在内核中操作呢。为了实现不经过用户缓冲区的copy,nio提供了零拷贝,请往下看

    再来偷个图


    NIO文件操作

    依然是浏览器请求磁盘上的文件a.txt,那么使用零拷贝会经历以下步骤:

    1. jvm发起sendfile()调起内核操作
    2. 内核读取a.txt,并存放到内核缓冲区(data to kernel)
    3. 内核将缓冲区(data to kernel)里的内容写入到 内核的另一个缓冲区(data to target socket),写入网卡
    4. 完成后返回sendfile()系统调用

    零拷贝的方式显然比传统io减少了2次从内核到用户,从用户到内核的copy过程,只是在内核空间里做了2次缓冲区数据的copy(对于操作系统来说,这2次缓冲区的copy也是可以合并成一次的,不再深究)

    零拷贝的问题:
    假设另一个场景,浏览器请求磁盘文件b.txt,并需要吧b.txt里的sb都替换成xxx。
    上述的零拷贝,看起来不能满足这个场景,因为使用零拷贝的只调用一次sendfile(),剩下的操作都有内核完成,jvm不再介入了。
    那么,如何解决这个问题呢?

    内存映射可以解决这个问题,将内核空间缓冲区的内容映射到jvm内存里,通过jvm,即可操作文件内容

    相关文章

      网友评论

          本文标题:NIO零拷贝

          本文链接:https://www.haomeiwen.com/subject/fhronhtx.html