mmap 共享内存深入总结
概述
mmap()系统调用在调用进程的虚拟地址空间中创建一个新的内存映射。munmap()系统调用执行逆操作,即从进程的地址空间删除一个映射。
映射可以分为两种:基于文件的映射和匿名映射。文件映射将一个文件区域中的内容映射到进程的虚拟地址空间中。匿名映射(通过使用MAP_ANONYMOUS)标记或映射/dev/zero来创建)并没有对应的文件区域,该映射中的字节会被初始化为0。
映射既可以是私有的(MAP_PRIVATE),也可以是共享的(MAP_SHARED)。这种差别确定了在共享内存上发生的变更的可见性,对于文件映射来讲,这种差别还确定了内核是否会将映射内容上发生的变更传递到底层文件上。当一个进程使用MAP_PAIVATE映射一个文件之后,在映射内容上发生的变更对其他进程是不可见的,并且也不会反应到映射文件上。MAP_SHARED文件映射的做法则相反——在映射上发生的变更对其他进程可见并且会反应到映射文件上。
尽管内核会自动地将发生在一个MAP_SHARED映射内容上的变更反应到底层文件上(pdflush线程),但它不保证合适完成这个操作。应用程序可以使用msync()系统调用来显示地控制一个映射内容何时与映射文件进行同步。
内存映射有多种用途:
- 分配进程私有的内存(私有匿名映射)
- 对一个进程的文本段和初始化数据段中的内容进行初始化(私有文件映射)
- 在通过fork()关联起来的进程之间共享内存(共享匿名映射)
- 执行内存映射I/O,还可以将其与无关简称之间的内存共享结合起来(共享文件映射)
在访问一个映射的内容时可能会遇到两个信号。如果在访问映射时违反了映射之上的保护规则(或访问一个当前未被映射的地址),那么就会产生一个SIGSEGV信号。对于基于文件的映射来讲,如果访问的映射部分在文件中没有相关区域与之对应(即映射大于底层文件,但仍算映射了,而不是未映射),那么就会产生一个SIGBUS信号。
交换空间过度利用允许系统给进程分配比实际可用的RAM与交换空间之和更多的内存。过度利用之所以可能是因为所有进程都不会全部用完为其分配的内存。使用MAP_NORESERVE标记可以控制每个mmap()调用的过度利用情况,而是用/proc文件则可以控制整个系统的过度利用情况。
mremap()系统调用允许调整一个既有映射的大小。remap_file_pages()系统调用允许创建非线性文件映射。
对于mmap()映射文件和read()文件来说,read()在读次数少的情况下比mmap()快。因为虽然mmap()不需要read()的那一次内存拷贝,但是硬件的发展,使得内存拷贝消耗时间极大降低了。而且mmap()的开销在于缺页中断,处理任务比较多。并且,mmap之后,再有读操作不会经过系统调用,所以在LRU比较最近使用的页时并不占优势,容易被换出内存。所以,普通读的情况下(排除反复读),read()通常比mmap()来得更快。
关于mmap,这里有一张图挺有意思的:mmap 文件映射内存详解 。
posted on 2019-02-06 00:17 TestCNBlogss 阅读(782) 评论(0) 编辑 收藏 举报