V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kaiser1992
V2EX  ›  程序员

如何理解内存映射文件?

  •  
  •   kaiser1992 · 2017-09-11 15:54:41 +08:00 · 3581 次点击
    这是一个创建于 2634 天前的主题,其中的信息可能已经有所发展或是发生改变。
    有以下几个问题:
    1、什么是内存映射文件?
    2、使用内存映射文件的好处是什么?
    第 1 条附言  ·  2017-09-11 18:08:10 +08:00
    补充个问题:
    Windows 中也分内核空间和用户空间,那么 IO 读取数据的时候也需要将数据先读到内核空间然后再复制到用户空间吗?
    16 条回复    2017-09-12 21:42:56 +08:00
    xenme
        2
    xenme  
       2017-09-11 18:24:36 +08:00 via iPhone
    直接读写就是需要经过中转。内存映射文件就是跳过了内核,不需要再次复制
    misaka20038numbe
        3
    misaka20038numbe  
       2017-09-11 18:37:42 +08:00
    就像你家的院子,只要知道地址,谁都可以来。
    kaiser1992
        4
    kaiser1992  
    OP
       2017-09-11 18:44:45 +08:00
    @xenme windows 中直接读写 IO 也需要复制?
    kaiser1992
        5
    kaiser1992  
    OP
       2017-09-11 18:50:20 +08:00
    @misaka20038numbe 这是进程之间实现通信的一种方式
    firemiles
        6
    firemiles  
       2017-09-11 19:07:04 +08:00
    @kaiser1992 内核态数据传到用户态都需要复制吧,除非映射
    kaiser1992
        7
    kaiser1992  
    OP
       2017-09-11 20:18:09 +08:00
    @firemiles windows 中也需要?
    stephen9357
        8
    stephen9357  
       2017-09-11 21:43:17 +08:00
    不需要,只要把同样物理地址再映射一份到用户态地址空间就可以了。参考 DO_DIRECT_IO 和 MDL。
    kaiser1992
        9
    kaiser1992  
    OP
       2017-09-11 22:25:36 +08:00
    @stephen9357 windows 中的普通 IO 有从内核空间到用户空间复制数据这个过程吗?
    xenme
        10
    xenme  
       2017-09-11 22:44:13 +08:00 via iPhone
    @kaiser1992 一般 io 都是有的
    ryd994
        11
    ryd994  
       2017-09-12 08:40:08 +08:00
    mmap 的基础是 virtual memory (不是 windows 的虚拟内存)
    当访问的虚拟地址不在内存里的时候,会 page fault 给内核,内核如果发现这是个 mmap,就会从硬盘读取数据到某段内存,然后把相应的内存页映射到这个虚拟地址

    至于 io 过程中的复制,主要是说 read 和 write 这两个
    我们看 POSIX read: ssize_t read(int fildes, void *buf, size_t nbyte);
    这里 buffer 就是用户空间内存
    而 io 读取是先读到内核空间的缓存里,再从缓存复制到 buf,这就是一次内存拷贝
    写也是同理

    @xenme 跳过内核?喵喵喵?内核还负责翻译虚拟地址呢,你这么厉害能跳过内核了?只有 DOS 才能这么玩
    stephen9357
        12
    stephen9357  
       2017-09-12 11:50:05 +08:00
    @kaiser1992 你说的普通 IO 是指什么?
    使用 Buffered IO 还是 Direct IO,甚至两者都不用都可以,取决于处理该 IO 的设备,可以下载 osr 的 devicetree 查看具体某个设备对象的 flags。
    可以参考 ReactOS 的 IO 管理器代码 https://github.com/reactos/reactos/blob/31b47ad45e6384dd538ebfee33c4829945cf2eee/reactos/ntoskrnl/io/iomgr/iofunc.c#L2695
    kaiser1992
        13
    kaiser1992  
    OP
       2017-09-12 12:39:41 +08:00
    @stephen9357 谢谢,directIO 的原理是不需要通过内核空间?
    kaiser1992
        14
    kaiser1992  
    OP
       2017-09-12 12:41:28 +08:00
    @stephen9357 也就是说 DirectIO 是内存映射的一种实现?
    stephen9357
        15
    stephen9357  
       2017-09-12 21:19:54 +08:00
    @kaiser1992 DO_DIRECT_IO 也需要内核地址空间。如果使用 DO_BUFFERED_IO,内核会新分配一个 buffer,对内容进行读写操作,最终将该 buffer 拷贝到用户态,而 DO_DIRECT_IO 则不需要拷贝,只是把应用层传递的 buffer 在内核重新映射一次,这样两块地址空间都对应同一块物理内存,就不需要拷贝了,改了这里就是改了那里。
    kaiser1992
        16
    kaiser1992  
    OP
       2017-09-12 21:42:56 +08:00
    @stephen9357 谢谢
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1087 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 22:28 · PVG 06:28 · LAX 14:28 · JFK 17:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.