1.mmap()mmap()系统调用在调用进程的虚拟地址空间中创建一个新的内存映射。映射分2种:1.文件映射:文件映射将一个文件的一部分直接映射到调用进程的虚拟内存中。2.匿名映射:一个匿名映射没有对应的文件。相反,这种映射的分页会被初始化为0.一个进程的映射中的内存可以与其他进程中的映射共享(即各个子进程的页表条目指向 RAM 中相同的分页)。这种情况会存在2种情况发生:1.当两个进程映射了一个文件的同一个区域时,它们会共享物理内存的相同分页2.通过 fork() 创建的子进程会继承父进程的映射的副本,并且这些映射所引用的物理内存分页与父进程中相应映射所引用的分页相同。当2个或者多个进程共享相同分页时,每个进程都有可能看到其他进程对分页内容作出的改变,这当然要取决于映射是私有的还是共享的:1.私有映射(MAP_PRIVATE):在映射内容上发生的变更对其他进程是不可见的,对于文件映射来说,变更将不会在底层文件上进行。尽管一个私有映射的分页在上面介绍的情况中,初始时是共享的,但对映射内容作出的变更对各个进程来讲是私有的。内核使用了写时复制技术完成了这个任务。这意味着,当一个进程试图修改一个分页的内容时,内核首先会为该进程创建一个新分页,并将需要修改的分页中的内容复制到新分页中(以及调整进程的页表)。正因为这个原因,MAP_PRIVATE 映射会被称为私有,写时复制映射。2.共享映射(MAP_SHARED):在映射内容上发生的变更对所有共享同一个映射的其他进程都是可见的,对于文件映射来说,变更将会发生在底层文件上。私有文件映射:映射的内容被初始化为一个而文件区域的内容。多个映射同一个文件的进程初始时会共享同样的内存物理分页,但系统使用写时复制技术使得一个进程对映射所做的变更对其他进程不可见。这种映射的主要用途是使用一个文件的内容来来初始化一块内存区域。一些常见的例子包括根据二进制可执行文件或共享文件的相应部分来初始化一个进程的文件和数据段。私有匿名映射:每次调用 mmap() 创建一个私有映射时都会产生一个新映射,该映射与同一进程创建的其他匿名映射是不同的(即不会共享物理分页)。尽管子进程会继承父进程的映射,但写时复制语义确保了 fork() 之后父进程和子进程不会看到其他进程对映射所做的变更。匿名映射的主要用途是位一个进程分配新(用0填充)的内存(如在分配大块内存时用 malloc()会为此使用 mmap())。共享文件映射:所有映射一个文件同一区域的进程会共享同样的内存物理分页,这些分页的内容将被初始化为该文件区域。对映射内容的修改将直接在文件中进行。这种映射主要用于2个用途:第一,它允许内存映射IO, 这表示一个文件会被加载到进程的虚拟内存中的一个区域中并且对该区域的变更会自动被写入到这个文件中。因此,内存映射IO 为使用 read(),write()来执行文件IO这种做法提供了一种替代方案。这种映射的第二个用途是允许无关进程共享一块内容以便以一种类似于System V 共享内存段的方式来执行(快速)IPC。共享匿名映射:与私有匿名映射一样,每次调用 mmap() 创建一个共享匿名映射时都会产生一个新的,与任何其他映射不共享分页的截然不同的映射。这里的区别是映射的分页不会被写时复制。这意味着,当一个子进程在 fork() 之后继承映射,父进程和子进程共享同一的 RAM分页,并且一个进程对映射内容所作出的变更会对其他进程可见。共享匿名映射允许以一种类似于 System V 共享内存段的方式来进行 IPC, 但只有相关进程可以这么做。区别:私有指同一个进程?私有匿名映射 和 共享匿名映射区别: 有没有写时复制,写时复制确保 父子进程对映射区域的变更不可见。而共享匿名映射,没有写时复制,父子进程对相关映射是可见的。私有:只有自己可见共享:其他进程也可见私有:每次都是新的映射共享:共享映射一个进程在执行 exec() 后映射会丢失,但通过 fork() 创建的子进程会继承映射,映射类型(MAP_PRIVATE 和 MAP_SHARED) 也会被继承。2.文件映射创建一个文件映射的步骤:1.获取一个文件的描述符,通常通过调用 open() 来获取2.将文件描述符作为 fd 参数,传入 mmap() 中执行上面操作之后,mmap() 会将打开的文件的内容映射到调用进程的地址空间。一旦 mmap() 被调用之后就能够关闭文件描述符了,而不会对映射产生任何影响。私有文件映射用途:1.允许多个执行统一程序或者使用同一个共享库的进程共享同样(只读的)文本段,它是从底层可执行文件或库文件的相应部分映射而来的。 //文本段2.映射一个可执行文件或共享库的初始化数据段。这种映射会被处理成私有,使得对映射数据段内容的变更不会发生在底层文件上。//全局数据段mmap() 的这2种用法通常对程序是不可见的,因为这些映射是由程序加载器和动态链接器创建的。共享文件映射:当多个进程创建了同一个文件区域的共享映射时,它们会共享同样的内存物理分页。此外,对映射内容的变更将会反应到文件上。共享文件映射存在2个用途: 1.内存映射IO由于共享文件映射中的内容是从文件初始化而来,并且对映射内容所做的变更都会自动反应到文件上,因此可以简单的通过访问内存中的字节来执行文件IO,而依靠内核来确保对内存的变更会被传递到映射文件上。(一般来说,一个程序会定义一个结构化数据类型来与磁盘文件中的内容对应起来,然后使用该数据类型来转换映射的内容)这项技术被称为内存映射IO,它是使用 read() 和 write() 来访问文件内容这种方法的替代方案。内存映射IO具备2个潜在的优势:1.使用内存访问来代替 read() 和 write() 系统调用能够简化一些应用程序的逻辑2.在一些情况下,它能够比使用传统的 IO 系统调用执行文件IO这种做法提供更好的性能。内存映射IO之所以能够带来性能优势原因如下:1.正常的 read,write需要2次传输:一次是在文件和内核高速缓冲区之间,另外一次是在高速缓冲区与用户空间缓冲区之间。使用 mmap() 就无需第二次传输了,对于输入来讲,一旦内核将相应的文件块映射到内存之后,用户进程就能够使用这些数据了。对于输出来讲,用户进程仅仅需要修改内存中的内容,然后可以依靠内核管理器来自动更新底层的文件。(少了一次传输)2.除了节省了内核空间和用户空间之间的一次传输之外,mmap() 还能够通过减少所需使用的内存来提示性能。当使用 read,write时,数据将别保存到2个缓冲区中:一个位于用户空间,另外一个位于内核空间。当使用 mmap() 时,内核空间和用户空间会共享同一个缓冲区。此外,如果多个进程正在同一个文件上执行IO,那么它们通过使用 mmap() 就能够共享同一个内核缓冲区,从而能够节省内存的消耗。(减少使用的内存)内存映射IO所带来的性能优势在大型文件中执行重复随机访问时最有可能体现出来。如果顺序的访问一个文件,并且假设执行IO时使用的缓冲区大小足够大以至于能够避免执行大量的IO系统调用,那么与 read,write 相比,mmap() 带来的性能上的提升就非常有限或者说根本没有带来性能提升。性能提升之所以有限是因为不管使用何种技术,整个文件内容在磁盘和内存之间只传输一次,效率的提升主要得益于减少了用户空间和内存空间的一次数据传输,并且与磁盘IO所需的时间相比,内存使用量的降低通常是可以忽略的。内存映射IO也有缺点。对于小数据量IO来讲,内存映射IO的开销(即映射,分页故障,接触映射以及更新硬件内存管理单元的超前转换缓冲器)实际上要比简单的read,write大。此外,有些时候内核难以高效的处理可写入映射的回写。2.IPC由于所有使用同样文件区域的共享映射的进程共享同样的内存物理分页,因此共享文件映射的第二个用途就是作为一种IPC方法。这种共享内存区域与 System V 共享内存对象之间的区别在于,区域上的内容的更变会反应到底层的映射文件上。这种特性对于那些需要共享内容在应用程序或系统重启时能够持久化的应用程序来说是非常有用的。3.同步映射区域:msync(void *addr, size_t length, int flags)内核会自动将发生在 MAP_SHARED 映射内容上的变更写入到底层文件中的,但默认情况下,内核不保证这种同步操作会在何时发生。msync()系统调用能够让应用程序显示的控制何时完成共享映射与映射文件之间的同步。flags 取值:MS_SYNC : 执行一个同步的文件写入。这个调用会阻塞直到内存区域中所有被修改过的分页被写入底层磁盘为止。MS_ASYNC : 执行一个异步写入。内存区域中被修改的分页会在后面某个时刻被写入磁盘并立即在相应文件区域中执行read()的其他进程可见。另外一种区分这两个值的方式可以表述为,在 MS_SYNC操作之后,内存区域会与磁盘同步,而在 MS_ASYNC之后,内存区域仅仅是与内核高速缓冲区同步。如果在 MS_ASYNC 操作之后不采取进一步的动作,那么内存区域中被修改过的分页最终会作为由 pdflush 内核线程执行的自动缓冲区刷新的一部分被写入磁盘。在Linux 上存在2种更快的发动输出的方法,在 msync() 调用之后,可以在映射对应的文件描述符上执行一个 fsync() 或者 fdatasync()。这个调用会阻塞,直到快速缓冲区与磁盘同步为止。MS_INVALIDATE : 使映射数据的缓存副本无效。当内存区域中所有被修改过的分页被同步到文件中之后,内存区域中所有与底层不一致的分页会被标记为无效。当下次引用这些分页时,会从文件中相应的位置处复制相应的分页内容。其结果是,其他进程对文件做出的所有更新将会在内存区域中可见。4.匿名映射匿名映射是一种没有对应文件的映射。在Linux 中,使用 mmap() 创建匿名映射存在2种不同但等级的方法:1.在 flags 中指定 MS_ANONYMOUS 并将 fd 指定为 -1.2.打开 /dev/zero 设备文件,并将得到的文件描述符传递给 mmap()/dev/zero 是一个虚拟的设备,从中读取数据总是返回0,而写到这个设备的数据总是被丢弃。5.MAP_NORESERVE 和 过度利用交换空间懒交换预留:如果内核总是为此类映射分配(或者预留)足够的交换空间,那么很多交换空间可能会被浪费。相反,内核可以只在需要的时候用到映射分页的时候(即当应用程序访问分页时)为它们预留交换空间,这种方法称为懒交换预留。它的一个优点是,应用程序总共使用的虚拟内存量能够超过RAM+交换空间的总量。换个角度来看,懒交换空间允许交换空间被过度利用。OOM 杀手:上面提到的当使用懒交换空间时,如果应用程序试图使用整个映射的话就会导致内存被耗尽。在这种情况下,内核会通过杀死进程来缓解内存消耗情况。内核中用来在内存被耗尽时选择杀死哪个进程的代码通常被称为 out-of-memory(OOM)杀手。6.非线性映射: remap_file_pages使用 mmap() 创建的文件映射是连续的:映射文件的分页与内存区域的分页存在一个顺序的,一对一的对应关系。可以使用多个带 MAP_FIXED 标记的 mmap() 调用创建非线性映射。然后这种方法的伸缩性不够好,其问题在于其中的每个 mmap() 调用都会创建一个独立的内核虚拟内存区域(VMA)数据结构。每个 VMA 的配置都需要花费时间并且会消耗一些不可交换的内核内存。此外,大量的VMA会降低虚拟内存管理器的性能。特别的,当存在数以万计的 VMA 时处理每个分页故障所花费的时间会大幅提高。/proc/PID/maps 中的每一行表示一个 VMA mmap();
munmap();
mprotect();
msync();
fsync();
fdatasync();
mremap();
remap_file_pages();

49.Linux/Unix 系统编程手册(下) -- 内存映射相关推荐

  1. linux/unix系统编程手册11-15

    title: linux/unix编程手册-11_15 date: 2018-05-27 11:53:07 categories: programming tags: tips linux/unix编 ...

  2. Linux/UNIX系统编程手册gg

    Linux系统: "所见皆文件" 一个比较好的博客 一.Linux基础操作 Linux系统目录: bin:存放二进制可执行文件 boot:存放开机启动程序 dev:存放设备文件: ...

  3. Linux/Unix系统编程手册 第三章:系统编程概念

    本章介绍系统编程的基础概念和一些后续章节用到的函数及头文件,并说明了可移植性问题. 系统调用是受控的内核入口,通过系统调用,进程可以请求内核以自己的名义去执行某些动作,比如创建子进程,执行I/O操作, ...

  4. Linux/Unix系统编程 五:进程

    进程是一个可执行程序的实例. 一.linux系统进程管理 1.进程管理的作用 判断机器健康状态 查看系统中所有进程 杀手进程 2.查看系统进程 1.ps -aux BSD操作系统格式: TTY说明: ...

  5. Linux系统编程手册-源码的使用

    Linux系统编程手册-源码的使用 转自:http://www.cnblogs.com/pluse/p/6296992.html 第三章后续部分重点介绍了后面章节所要使用的头文件及其实现,主要如下: ...

  6. Linux/Unix系统下nginx+php安装简明教程

    本文转载自Linux/Unix系统下nginx+php安装简明教程,请保留转载信息~ 一.安装nginx: 1. 安装pcre库,nginx的rewrite模板需用到pcre库: mkdir -p / ...

  7. 在Linux/Unix系统下用iconv命令处理文本文件中文乱码问题

    iconv命令是运行于linux/unix平台的文件编码装换工具.当我们在linux/unix系统shell查看文本文件时,常常会发现文件的中文是乱码的,这是由于文本文件的编码与当前操作系统设置的编码 ...

  8. 5w字总结 Unix系统编程学习笔记(面试向)(Unix环境高级编程/Unix环境程序设计)

    文章目录 一.计算 C语言的数据表示与处理 计算 C语言的基本运算操作 内存表和符号表 类型转换 函数类型的分析 指令 复合指令 句法 函数 函数激活(Activation Record) 函数激活定 ...

  9. ①Linux简明系统编程(嵌入式公众号的课)---总课时12h

    10.09 注意:这个是Linux高级编程的简明教程,是Linux应用程序的开发,而不是底层程序的开发. 内容是关于操作系统和网络编程的吗? Linux简明系统编程 〇.课程思维导图 〇.会用到的头文 ...

  10. 【Linux】系统编程之文件(标准I/O库)

    目录 一.文件I/O与标准I/O的区别(open与fopen) 1.来源 2.移植性 3.适用范围 4.文件IO层次 5.缓冲 二.函数fopen.fwrite.fread.fseek.fclose ...

最新文章

  1. iOS开发异常错误总结之——wait_fences: failed to receive reply: 10004003
  2. UI基础篇-iOS中简单图片浏览器的实现
  3. Docker selenium自动化 - windows版docker的安装与运行环境检测
  4. win32应用程序创建流程
  5. python中lines是什么类型_python里的splitlines详解
  6. 幅度和幅值有区别吗_童溢金:白银期货和现货白银的区别在哪,你知道吗?
  7. H.263 H.263+ Payload Type
  8. word如何设置长宽高_word怎样设置图片长宽
  9. RegularExpressions(2) RegularExpressions 支持的正则表达式语法
  10. 号称2020最轻薄的5G旗舰,这款手机 你不看看吗?
  11. 深度分析Spring中的构造器注入
  12. mysql源码目录在哪_Mysql源码学习——源码目录结构
  13. springboot项目启动成功后执行一段代码的两种方式
  14. leetcode python3 简单题160. Intersection of Two Linked Lists
  15. 流水线作业调度问题-动态规划(运用Johnson算法)
  16. Oracle JDK商用费用分析
  17. 记录常用的chrome插件
  18. php中的eof是什么意思,在C++中eof是什么意思?
  19. 解决模拟人生3(SIM 3)闪退问题
  20. MySQL事务之脏读问题

热门文章

  1. 选择条件WD_SELECT_OPTIONS_20
  2. Java EE API
  3. 几种常见排序算法的时间复杂度和简单描述
  4. 苹果“大力鼠”不敌微软“鲨”
  5. 用R语言分析我和男友的聊天记录
  6. 从大数据角度看你的信用借贷
  7. 错过了蓝月亮,你还有我们~~只此一次!
  8. 走进R语言的世界——简单数据处理
  9. Python——集合与字典练习
  10. Java多线程——Condition条件