《Linux内核 学习笔记》--- 第二章 内存管理

  • 2.9 mmap 概述
    • 问题1:请阅读Linux内核中mmap相关代码,找出第二次调用mmap会成功的原因?
    • 问题2:在一个播放系统中同时打开几十个不同的高清视频文件,发现播放有些卡顿,打开视频文件是用mmap函数,请简单分析原因。

2.9 mmap 概述

mmap/munmap接口是用户空间最常用的一个系统调用接口,
无论是在用户程序中分配内存、读写大文件、链接动态库文件,还是多进程间共享内存,都可以看到mmap/munmap的身影。

mmap/munmap函数声明如下:

#include <sys/mman.h>
void *mmap(void *addr, size_t length , int prot, int flags, int fd , off_t offset);
int munmap(void *addr, size_t length);

❑ addr:用于指定映射到进程地址空间的起始地址,为了应用程序的可移植性,一般设置为NULL,让内核来选择一个合适的地址。
❑ length:表示映射到进程地址空间的大小。
❑ prot:用于设置内存映射区域的读写属性等。
❑ flags:用于设置内存映射的属性,例如共享映射、私有映射等。
❑ fd:表示这个是一个文件映射,fd是打开文件的句柄。
❑ offset:在文件映射时,表示文件的偏移量。

prot参数通常表示映射页面的读写权限,可以有如下参数组合。
❑ PROT_EXEC:表示映射的页面是可以执行的。
❑ PROT_READ:表示映射的页面是可以读取的。
❑ PROT_WRITE:表示映射的页面是可以写入的。
❑ PROT_NONE:表示映射的页面是不可访问的。

flags参数也是一个很重要的参数,有如下常见参数。
❑ MAP_SHARED:创建一个共享映射的区域。多个进程可以通过共享映射方式来映射一个文件,这样其他进程也可以看到映射内容的改变,修改后的内容会同步到磁盘文件中。
❑ MAP_PRIVATE:创建一个私有的写时复制的映射。多个进程可以通过私有映射的方式来映射一个文件,这样其他进程不会看到映射内容的改变,修改后的内容也不会同步到磁盘文件中。
❑ MAP_ANONYMOUS:创建一个匿名映射,即没有关联到文件的映射。
❑ MAP_FIXED:使用参数addr创建映射,如果在内核中无法映射指定的地址addr,那mmap会返回失败,参数addr要求按页对齐。如果addr和length指定的进程地址空间和已有的VMA区域重叠,那么内核会调用do_munmap()函数把这段重叠区域销毁,然后重新映射新的内容。
❑ MAP_POPULATE:对于文件映射来说,会提前预读文件内容到映射区域,该特性只支持私用映射。

参数fd可以看出mmap映射是否和文件相关联,因此在Linux内核中映射可以分成匿名映射和文件映射。
❑ 匿名映射:没有映射对应的相关文件,这种映射的内存区域的内容会被初始化为0。
❑ 文件映射:映射和实际文件相关联,通常是把文件的内容映射到进程地址空间,这样应用程序就可以像操作进程地址空间一样读写文件。

最后根据文件关联性和映射区域是否共享等属性,又可以分成如下4种情况:

  1. 私有匿名映射
    当使用参数fd=-1 且 flags= MAP_ANONYMOUS | MAP_PRIVATE时,创建的mmap映射是私有匿名映射。
    私有匿名映射最常见的用途是在glibc分配大块的内存中,当需要分配的内存大于MMAP_THREASHOLD(128KB)时,glibc会默认使用mmap代替brk来分配内存。

  2. 共享匿名映射
    当使用参数 fd=-1 且 flags= MAP_ANONYMOUS | MAP_SHARED 时,创建的mmap映射是共享匿名映射。
    共享匿名映射让相关进程共享一块内存区域,通常用于父子进程之间通信。
    创建共享匿名映射有如下两种方式。
    (1)fd=-1且flags= MAP_ANONYMOUS | MAP_SHARED。
    在这种情况下,do_mmap_pgoff()->mmap_region()函数最终会调用shmem_zero_setup()来打开一个“/dev/zero”特殊的设备文件。
    (2)另外一种是直接打开“/dev/zero”设备文件,然后使用这个文件句柄来创建mmap。

上述两种方式最终都是调用到shmem模块来创建共享匿名映射。

  1. 私有文件映射
    创建文件映射时flags的标志位被设置为MAP_PRIVATE,那么就会创建私有文件映射。
    私有文件映射最常用的场景是加载动态共享库。

  2. 共享文件映射
    创建文件映射时flags的标志位被设置为MAP_SHARED,那么就会创建共享文件映射。
    如果prot参数指定了PROT_WRITE,那么打开文件时需要指定O_RDWR标志位。
    共享文件映射通常有如下两个场景。
    (1)读写文件。
    把文件内容映射到进程地址空间,同时对映射的内容做了修改,内核的回写机制(writeback)最终会把修改的内容同步到磁盘中。
    (2)进程间通信。
    进程之间的进程地址空间相互隔离,一个进程不能访问到另外一个进程的地址空间。如果多个进程都同时映射到一个相同文件时,就实现了多进程间的共享内存通信。如果一个进程对映射内容做了修改,那么另外的进程是可以看到的。

mmap机制在Linux内核中的代码流程

问题1:请阅读Linux内核中mmap相关代码,找出第二次调用mmap会成功的原因?

===>
查看mmap系统调用的代码实现,在do_mmap_pgoff()->mmap_region()函数里有如下一段代码:
这里再一次看到find_vma_links()函数
find_vma_links()函数会遍历该进程中所有的VMAs,
当检查到当前要映射的区域和已有的VMA有些许的重叠时,该函数都返回-ENOMEM,
然后在mmap_region()函数里调用do_munmap()函数,把这段将要映射区域先销毁,然后重新映射,
这就是第二次映射同样的地址并没有返回错误的原因。

问题2:在一个播放系统中同时打开几十个不同的高清视频文件,发现播放有些卡顿,打开视频文件是用mmap函数,请简单分析原因。

使用mmap来创建文件映射时,由于只建立了进程地址空间VMA,并没有马上分配page cache和建立映射关系。
因此当播放器真正读取文件时,产生了缺页中断才去读取文件内容到page cache中。
这样每次播放器真正读取文件时,会频繁地发生缺页中断,然后从文件中读取磁盘内容到page cache中,导致磁盘读性能比较差,从而造成播放视频的卡顿。

有些读者认为在创建mmap映射之后调用madvise(add, len,MADV_WILLNEED |MADV_SEQUENTIAL)可能会对文件内容提前进行了预读和顺序,读所有利于改善磁盘读性能,但实际情况是:
❑ MADV_WILLNEED会立刻启动磁盘IO进行预读,仅预读指定的长度,因此在读取新的文件区域时,要重新调用\2ADV_WILLNEED,显然它不适合流媒体服务的场景,内核默认的预读功能更适合问题2的场景。MADV_ WILLNEED比较适合内核很难预测接下来要预读哪些内容的场景,例如随机读。
❑ MADV_SEQUENTIAL适合问题2的场景,但是内核默认的预读功能也能很好的工作。

能够有效提高流媒体服务I/O性能的方法是增大内核的默认预读窗口,现在内核默认预读的大小是128KB,可以通过“blockdev --setra”命令来修改。

《Linux内核 学习笔记》--- 第二章 内存管理 2.9 mmap相关推荐

  1. 《深入理解Linux内核》笔记5:内存管理

    本文介绍内核如何给自己分配物理内存并管理.对应<深入>第8章. 在<深入>第2章"内存寻址"(或者是我博客中的这篇文章,点这里)中,已经介绍了内核如何给自己 ...

  2. [go学习笔记.第二章] 2.go语言的开发工具以及安装和配置SDK

    一.工具介绍: 1.Visual Studio Code 一个运行于Mac,Windows,和linux上的,默认提供Go语言的语法高亮的IED,可以安装Go语言插件,还可以支持智能提示,编译运行等功 ...

  3. 《Go语言圣经》学习笔记 第二章 程序结构

    Go语言圣经学习笔记 第二章 程序结构 目录 命名 声明 变量 赋值 类型 包和文件 作用域 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. Go语言小白学习笔记,几乎是书上的内 ...

  4. 操作系统进程学习(Linux 内核学习笔记)

    操作系统进程学习(Linux 内核学习笔记) 进程优先级 并非所有进程都具有相同的重要性.除了大多数我们所熟悉的进程优先级之外,进程还有不同的关键度类别,以满足不同需求.首先进程比较粗糙的划分,进程可 ...

  5. PhalAPI学习笔记 ——— 第二章接口服务请求

    PhalAPI学习笔记 --- 第二章接口服务请求 前言 接口服务请求 接口服务请求案例 自定义接口路由 开启匹配路由 配置路由规则 nginx apache 服务请求 结束语 前言 公司业务需要转学 ...

  6. 小吴的《机器学习 周志华》学习笔记 第二章 模型评估与选择

    小吴的<机器学习 周志华>学习笔记 第二章 模型评估与选择 上一周我们介绍了第一章的基础概念,这一次将带来第二章的前三节.后面的2.4 比较检验与2.5 偏差与方差,涉及概率论与数理统计概 ...

  7. 小吴的《机器学习 周志华》学习笔记 第二章 2.4 比较检验、2.5 偏差与方差

    小吴的<机器学习 周志华>学习笔记 第二章 2.4 比较检验. 2.5 偏差与方差 2.4 比较检验 上一周提到了实验的评价方法和性能量度,步骤简单可以看成:先使用某种实验评估方法测得学习 ...

  8. 机器人导论(第四版)学习笔记——第二章

    机器人学导论(第四版)学习笔记--第二章 2. 空间描述和变换 2.1 引言 2.2 描述:位置.姿态与位姿 2.3 映射:从一个坐标系到另一个坐标系的变换 2.4 算子:平行,旋转和变换 2.5 总 ...

  9. 我的Linux内核学习笔记

    在开始今天的内容之前,其实有一些题外话可以和大家分享一下.自从工作以来,我个人一直都有一个观点.那就是怎么样利用简单的代码来说明开发中的问题,或者是解释软件中的原理,这是一个很高的学问.有些道理看上去 ...

  10. 操作系统 课堂笔记 第二章 进程管理

    第二章 进程管理 2.1 本章导学 基本内容: (1)进程的基本概念. (2)进程控制. (3)进程间互斥与同步. (4)进程通信. (5)进程调度. (6)进程死锁. (7)线程. 学习重点: (1 ...

最新文章

  1. Javascript实现边框闪动
  2. 操作系统课设--使用信号量解决生产者/消费者同步问题
  3. python函数定义与使用
  4. nginx配置反向代理示例
  5. 【C#】分享一个弹出容器层,像右键菜单那样召即来挥则去
  6. hibernate+struts2整合jar包冲突
  7. 手动选择显示_为什么考驾照的人多数选择C1而不是C2?老教练说出了真相....
  8. python set去重 字典 计算求和_python字典set方法的特殊方法
  9. numpy提供的快速的元素级数组函数
  10. Java 会是未来第一编程语言吗?
  11. 一键搭建自己的网络加速器
  12. 视频教程-EXCEL VBA编程进阶-Office/WPS
  13. (亲测可用)Redis远程连接频繁掉线应对策略 -- 还能让你不知不自觉中在笑声中掌握Redis命令
  14. 基于银河麒麟 V10 系统安装和卸载 DM8 数据库
  15. 论坛报名 | 语音与自然语言处理的最新突破和前沿趋势。道翰天琼认知智能平台为您揭秘新一代人工智能-1。
  16. 打光篇-Radiometric Photometric概念
  17. 合肥市直计算机知识pdf,事业单位计算机专业知识整理(全)-20210419115129.pdf-原创力文档...
  18. 【网络篇】第十七篇——IP协议详解
  19. 解决Error in file(con, “w“) : cannot open the connection问题
  20. 机器学习(决策树四)——简述 剪枝

热门文章

  1. 【年终总结】你好2021,再见2020。
  2. 边境的悍匪—机器学习实战:第五章 支持向量机
  3. Android面试题汇总(适合Android中高级开发工程师)
  4. 计算机英语作文初中,初中关于电脑的英语作文
  5. 联想计算机系统重装,联想笔记本电脑重装系统教程
  6. CSS3实现骗人版无缝轮播图
  7. C++核心编程-5 文件操作
  8. 计算机在英语翻译上的运用,有道如何在网页上翻译一句话,有道网页上的字翻译怎么用...
  9. CS5298 Type-C/DP1.4 到 HDMI 2.1转换芯片|TYPEC转HDMI2.1转换芯片|DP1.4转HDMI2.1转换芯片
  10. TensorFlow Serving Introduction