14 [虚拟化] 虚存抽象;Linux进程的地址空间

14 [虚拟化] 虚存抽象;Linux进程的地址空间

南京大学操作系统课蒋炎岩老师网络课程笔记。

视频:https://www.bilibili.com/video/BV1N741177F5?p=14
讲义:http://jyywiki.cn/OS/2021/slides/10.slides#/

本讲概述

程序 = 状态机;进程 = 状态机的执行(路径)

  • 状态机的状态由内存和寄存器(M,R)决定
    • 寄存器会在发生中断之后保存到进程的内存(内核栈)中
    • 内存呢?

虚存抽象:

  • 进程的地址空间
  • 分页机制
  • 分页机制和虚拟存储

进程的地址空间

进程的地址空间中有什么

进程的地址空间 = 内存中若干连续的 “段”,每一段是可访问的(读/写/执行)的内存,可能映射到某个文件和 / 或在进程间共享。

进程执行指令需要代码、数据、堆栈:

  • 代码(如main,%rip会从此处取出待执行的指令)
  • 数据(如static int x)
  • 堆栈(如int y)

地址空间中还有:

  • 动态链接库
  • 运行时分配的内存

以上这些都可以直接用指针访问。

那么,这个地址空间是怎么创建的呢?创建之后,我们还可以修改它吗?肯定是能的,如动态链接库可以动态地加载。

管理进程地址空间的系统调用

// 映射
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
int munmap(void *addr, size_t length);// 修改映射权限
int mprotect(void *addr, size_t length, int prot);

mmap的作用就是把磁盘文件的一部分直接映射到进程的内存中

说人话:在状态机上增加或者删除一段可访问的内存。

把文件映射到地址空间?

它们好像的确没什么区别:

  • 文件 = 字节序列
  • 内存 = 字节序列
  • 操作系统允许这样映射好像挺合理的,下一课中,ELF loader用mmap非常容易实现,解析出要加载哪部分到内存,然后直接mmap就完了。

查看进程的地址空间

pmap

pmap命令可以查看某个进程的地址空间:

pmap [PID]

动态链接 / 静态链接的地址空间

我们准备一个死循环C程序:

int main(){while (1);
}

分别用动态链接和静态链接的方式来编译它:

gcc test.c -o test_d.out
gcc -static test.c -o test_s.out

分别把得到的test_d.outtest_s.out后台执行并用pmap来查看它们的地址空间:

$ ./test_d.out &
[1] 5002
$ ./test_s.out &
[2] 5015pmap 5002
pmap 5015

分别得到动态链接和静态链接的pmap如下:

5002:   ./test_d.out
000055cfab135000      4K r-x-- test_d.out
000055cfab335000      4K r---- test_d.out
000055cfab336000      4K rw--- test_d.out
00007f26750a9000   1948K r-x-- libc-2.27.so
00007f2675290000   2048K ----- libc-2.27.so
00007f2675490000     16K r---- libc-2.27.so
00007f2675494000      8K rw--- libc-2.27.so
00007f2675496000     16K rw---   [ anon ]
00007f267549a000    164K r-x-- ld-2.27.so
00007f2675691000      8K rw---   [ anon ]
00007f26756c3000      4K r---- ld-2.27.so
00007f26756c4000      4K rw--- ld-2.27.so
00007f26756c5000      4K rw---   [ anon ]
00007fff1d64d000    132K rw---   [ stack ]
00007fff1d6cd000     12K r----   [ anon ]
00007fff1d6d0000      4K r-x--   [ anon ]
ffffffffff600000      4K --x--   [ anon ]total             4384K
5015:   ./test_s.out
0000000000400000    728K r-x-- test_s.out
00000000006b6000     24K rw--- test_s.out
00000000006bc000      4K rw---   [ anon ]
0000000000e17000    140K rw---   [ anon ]
00007fff1bf5b000    132K rw---   [ stack ]
00007fff1bfc5000     12K r----   [ anon ]
00007fff1bfc8000      4K r-x--   [ anon ]
ffffffffff600000      4K --x--   [ anon ]total             1048K

可以看到动态链接比静态链接多了很多动态链接库.so,占用的内存空间也较大。而通过ls -l命令,我们发现动态链接生成的可执行文件所占的磁盘空间更小。

pmap的实现

我们不禁好奇pmap是怎样实现的,可以通过追踪系统调用的strace工具来查看:

strace pmap 5002

实际上,我们多次强调过的一个概念:程序就是一个状态机,而这样一个状态机想要得到操作系统里的任何东西,都要通过系统调用,所以当我们想知道pmap这样的程序是怎样实现的,最好的办法就是去看一下它执行了哪些系统调用,因此说追踪系统调用的strace工具是十分有用的

言归正传,上述pmap指令的输出中最关键的是这一句:

openat(AT_FDCWD, "/proc/5002/maps", O_RDONLY) = 3

我们看到,pmap是去读/proc文件中相关进程号的内存信息maps。(关于/proc:linux /proc 详解)

我们发现了什么宝藏?

我们直接看一下上面动态链接的可执行文件的进程:

cat /proc/5--2/maps

输出:

55cfab135000-55cfab136000 r-xp 00000000 103:02 28869833                  /home/song/CppProjects/test_d.out
55cfab335000-55cfab336000 r--p 00000000 103:02 28869833                  /home/song/CppProjects/test_d.out
55cfab336000-55cfab337000 rw-p 00001000 103:02 28869833                  /home/song/CppProjects/test_d.out
7f26750a9000-7f2675290000 r-xp 00000000 103:02 8393695                   /lib/x86_64-linux-gnu/libc-2.27.so
7f2675290000-7f2675490000 ---p 001e7000 103:02 8393695                   /lib/x86_64-linux-gnu/libc-2.27.so
7f2675490000-7f2675494000 r--p 001e7000 103:02 8393695                   /lib/x86_64-linux-gnu/libc-2.27.so
7f2675494000-7f2675496000 rw-p 001eb000 103:02 8393695                   /lib/x86_64-linux-gnu/libc-2.27.so
7f2675496000-7f267549a000 rw-p 00000000 00:00 0
7f267549a000-7f26754c3000 r-xp 00000000 103:02 8393690                   /lib/x86_64-linux-gnu/ld-2.27.so
7f2675691000-7f2675693000 rw-p 00000000 00:00 0
7f26756c3000-7f26756c4000 r--p 00029000 103:02 8393690                   /lib/x86_64-linux-gnu/ld-2.27.so
7f26756c4000-7f26756c5000 rw-p 0002a000 103:02 8393690                   /lib/x86_64-linux-gnu/ld-2.27.so
7f26756c5000-7f26756c6000 rw-p 00000000 00:00 0
7fff1d64d000-7fff1d66e000 rw-p 00000000 00:00 0                          [stack]
7fff1d6cd000-7fff1d6d0000 r--p 00000000 00:00 0                          [vvar]
7fff1d6d0000-7fff1d6d1000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]

前面都好理解,是我们进程执行时的代码、数据、堆栈、动态链接库等,但是最后那三个:vvar、vdso、vsyscall是什么鬼?

vvar、vdso、vsyscall是什么鬼?

让内核和进程共享数据 (内核可写,进程只读)

  • vvar: 内核和进程共享的数据

  • vdso: 系统调用代码实现 (是操作系统的一部分)

  • vsyscall: (ffffffffff600000这么诡异的地址???)

  • 是普通系统调用的包装

    • 曾经的 exception-less syscall 实现,但存在安全问题
    • 依然存在,保持向后兼容

vsyscall 的例子

  • 时间:内核维护秒级的时间 (所有进程映射同一个页面)
    • 例子:time (2)
      • 我们甚至可以调试它
  • getcpu:per-CPU 映射页面

计算机系统里没有魔法!我们理解了 Linux 进程地址空间的全部!

使用共享内存与内核通信

有些系统调用不陷入内核也可以执行,使用共享内存和内核通信!

  • 内核线程在 spinning 等待系统调用的到来
  • 收到系统调用请求后立即开始执行
  • 进程 spin 等待系统调用完成
  • 如果系统调用很多,可以打包处理

实现虚拟存储:分页机制

需求分析

我们的操作系统看到的内存是真实的物理内存,而为各个线程提供的,即线程看到的是虚拟内存。那么,操作系统怎样事项这一虚拟化呢?

操作系统希望实现地址空间的管理(mmap、munmap API)

  • 进程的地址空间是由若干 “段” 组成的,但是操作系统只拥有一个物理地址空间(物理内存)
  • 操作系统需要
    • 为进程存储各个段的信息(例如在struct proc里)
    • 在物理内存中实际分配内存( pmm->alloc() )
    • 借助硬件的机制实现虚拟化 (CPU在执行用户进程时,强制进行地址翻译)

所以,我们需要一个函数 f:[0,M)→[0,M)f : [0,M) \rightarrow [0,M)f:[0,M)[0,M),把 ”虚拟地址“ 翻译为 ”物理地址“ ,毕竟我们真实的物理内存只有一份,fff 应当由操作系统控制,即应用程序不可见 fff

操作系统为每个进程准备一个映射函数 fff ,当进程运行时,fff 被 ”加载“ 到CPU上,此后该进程每次访问内存,都需要通过CPU上对应的 fff 来进行从该进程可见的虚拟内存到真实物理内存的映射,而该进程的任何越权访问物理内存地址,都将触发异常(缺页?)。

应当注意,我们的 fff 有以下几方面的要求:

  • 支持 fff 在运行时动态地进行修改(mmap,munmap)
  • 非常节约:fff 的存储开销必须远小于实际使用的内存,总不能为了维护映射函数 fff 所使用的内存比实际要使用的内存还多
  • 非常高效:因为每次访问内存都要计算 fff, 因此其实现需要非常高效

分页机制

把地址空间切成大小为 ppp 的 “页面” ,比如在x86中,页面大小为4KiB。只维护以页面为单位的映射,而非整个物理内存大小的虚拟内存到整个物理内存的映射。这样我们要维护:[0,M/p)→[0,M/p)[0,M/p) \rightarrow [0,M/p)[0,M/p)[0,M/p) 的映射。

我们有这样一个基本假设:进程内存地址的空间局部性,即绝大部分页面都没有映射,且映射一般都是连续的空间

Radix Tree(Trie) + TLB(Translation Lookaside Buffer)

在这里插入图片描述

32位机和64位机的分页寻址过程如图所示:

在这里插入图片描述
在这里插入图片描述

分页+保护:实现虚拟化

映射是页面到页面的,也就意味着映射的低位永远是0,4kiB的页面就会有12bits空闲,可以用来存储页面的存储保护等信息。

在这里插入图片描述

分页机制与虚拟存储

mmap并不需要为进程分配任何页面,只需要 “让操作系统知道这么映射” 就够了,进程访问页面会进入缺页进入操作系统。

操作系统并不需要在这一段创建的时候,就立即给进程分配内存,而是操作系统完全可以等到进程真正访问这个页面并发生缺页时,再去分配这块内存。当然,如果操作系统根据之前的映射发现进程访问的这块内存是不合法的,就会Segmentation Fault。

缺页

缺页时操作系统会得到缺页的地址(%cr2),根据操作系统维护的进程地址信息分配页面。

Memory-Mapped File:一致性

这样的设计也有些问题需要明确,比如:

  • 如果把页面映射到文件
    • 修改什么时候生效(立即生效,会造成大量的磁盘IO;等到unmap或者进程结束在生效,又太迟了)
    • 若干映射到同一个文件的进程(共享一份内存?各自有本地的副本?)

Takeaways and Wrap-up

虚拟化

  • 程序 = 状态机 (进程的地址空间里到底有什么)
  • 操作系统 = 状态机的管理者,借助硬件(物理状态机)实现多个并发执行的虚拟状态机(进程)
  • 状态机中的地址空间(虚拟地址空间)
    • 应用视角:用mmap系统调用管理
    • 硬件视角:用分页机制实现

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/532752.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

浏览器是指在用户计算机上,自考《网页设计与制作》测试题及答案

自考《网页设计与制作》测试题及答案学习是一个不断积累的过程,为帮助考生们更好地复习《与制作》科目知识点,以下是搜索整理的一份自考《网页设计与制作》测试题及答案,供参考练习,希望对大家有所帮助!想了解更多相关信息请持续关…

Ubuntu 18.04 安装OpenCV C++

Ubuntu 18.04 安装OpenCV C 构建并安装 仅构建核心模块 # 更新并安装依赖 # 更新并安装依赖 sudo apt update && sudo apt install -y cmake g wget unzip# 下载并解压包 wget -O opencv.zip https://github.com/opencv/opencv/archive/master.zip unzip opencv.zip…

html计算x的y,HTML5画布:旋转时计算x,y点

我开发了一个HTML5 Canvas应用程序,它涉及到读取一个xml文件,该文件描述了需要在画布上绘制的箭头,直形和其他形状的位置。的XML布局的HTML5画布:旋转时计算x,y点实施例:如果对象被旋转它涉及计算一个点的位…

(2021) 20 [虚拟化] 进程调度

(2021) 20 [虚拟化] 进程调度 南京大学操作系统课蒋炎岩老师网络课程笔记。 视频:https://www.bilibili.com/video/BV1HN41197Ko?p20 讲义:http://jyywiki.cn/OS/2021/slides/11.slides#/ 背景 — 机制与策略分离 机制:一个通用的、可定制…

计算机组装过程英文版,计算机组装与维护试题及答案(国外英文资料).doc

计算机组装与维护试题及答案(国外英文资料)计算机组装与维护试题及答案(国外英文资料)(1) choiceIn the following equipment, the input device is (b)A. b. b. c. c. c. d. d.In Windows 98, the combination of CTRL Alt Del is (c)A. cold start b. heat start c. interr…

make命令及makefile

make命令及makefile 转自:https://www.ruanyifeng.com/blog/2015/02/make.html Make 命令教程 作者: 阮一峰 日期: 2015年2月20日 代码变成可执行文件,叫做编译(compile);先编译这个&#…

局域网中计算机网络密码查看,Win10怎么查看电脑上已知的wifi网络密码

方法一:网络和共享中心查询1、在Windows 10桌面最左下角的【Windwos开始图标上右键】,在弹出的菜单中点击打开【网络连接】,如下图所示。2、在打开的网络连接设置中,双击已经连接的【无线网络名称】,在弹出的【WLAN状态…

(2021) 22 [持久化] 1-Bit的存储

(2021) 22 [持久化] 1-Bit的存储 南京大学操作系统课蒋炎岩老师网络课程笔记。 视频:https://www.bilibili.com/video/BV1HN41197Ko?p22 讲义:http://jyywiki.cn/OS/2021/slides/12.slides#/ 背景 回顾 操作系统是什么?一组对象 一组API…

计算机一级试题论述,计算机一级考试理论题及答案要点

计算机一级考试IT1必做题[1]. 著名的计算机科学家尼.沃思提出了________。A.数据结构+算法程序B.存储控制结构C.信息熵D.控制论[2]. 下面有关扫描仪的叙述中,错误的是________。A.分辨率是扫描仪…

(2021) 23 [持久化] I/O设备与驱动

(2021) 23 [持久化] I/O设备与驱动 南京大学操作系统课蒋炎岩老师网络课程笔记。 视频:https://www.bilibili.com/video/BV1HN41197Ko?p23 讲义:http://jyywiki.cn/OS/2021/slides/13.slides#/ 背景 很多人 (你们的同学们、家长们) 都有一个认识&…

计算机考研计划时间,2019计算机考研时间安排:复习时间规划

随着考研竞争越来越激烈,考研复习一定要做好规划,每天的时间要做好管理,分清轻重缓急,这样才能高效率复习。管理的5个原则,大家抓紧调整个人复习。小编还为大家精心准备了计算机考研复习资料还有计算机考研报考指导助力…

(2021) 24 [持久化] 文件系统API

(2021) 24 [持久化] 文件系统API 南京大学操作系统课蒋炎岩老师网络课程笔记。 视频:https://www.bilibili.com/video/BV1HN41197Ko?p24 讲义:http://jyywiki.cn/OS/2021/slides/14.slides#/ 背景 回顾 硬件视角:持久化的“层层抽象” 物…

计算机辅助应用的缩写有什么,计算机辅助设计的英文缩写是什么

2008-10-09是什么的英文缩写?BOBO......头型里的.....其实"BOBO头"准确的名称应该是BOB头。它是娃娃头的一种。BOB头有许多变种,标准的类似于樱桃小丸子的发型,专业发型师把它称为BOB。最初是由巴黎发型师Antoine 在1909年发明,但…

Linux中的硬链接和软链接

Linux中的硬链接和软链接 节选自南大蒋炎岩老师操作系统网络课程笔记:(2021) 24 [持久化] 文件系统API 硬(hard)链接 UNIX文件指针 在UNIX中,文件和目录完全不是同一个概念,虽然我们平时看着它们仿佛并列地躺在某个…

计算机win10开机音乐,大师传授win10系统电脑开机总是自动播放音乐的方案

今天小编分享一下win10系统电脑开机总是自动播放音乐问题的处理方法,在操作win10电脑的过程中常常不知道怎么去解决win10系统电脑开机总是自动播放音乐的问题,有什么好的方法去处理win10系统电脑开机总是自动播放音乐呢?今天本站小编教您怎么…

Linux中的tty、pts、pty等概念辨析

Linux中的tty、pts、pty等概念辨析 基本概念 tty、pty、pts、ptmx tty(终端设备的统称):tty一词源于Teletypes,或teletypewriters,原来指的是电传打字机,是通过串行线用打印机键盘通过阅读和发送信息的东…

(2021) 25 [持久化] 文件系统实现:FAT和UNIX文件系统

(2021) 25 [持久化] 文件系统实现:FAT和UNIX文件系统 南京大学操作系统课蒋炎岩老师网络课程笔记。 视频:https://www.bilibili.com/video/BV1HN41197Ko?p25 讲义:http://jyywiki.cn/OS/2021/slides/15.slides#/ 背景 回顾 应用眼中的文件…

用计算机模拟地球诞生,计算机模拟显示早期金星或像地球一样宜居

虽然金星的绰号是“地球的邪恶孪生化身”,但它和地球上的一切都不同:灼热、干燥并且被有毒烟云笼罩。不过,就在10亿或20亿年前,这两个任性的“兄弟”可能更加相似。最新的计算机模拟显示,早期的金星看上去和地球很像&a…

海南大学计算机原理,海南大学微机原理课件 第一章 计算机基础知识

第一章计算机基础知识数 制1.1一.计算机使用的数制及其相互转换 十进制(D)、二进制(B)、八进制(O)和十六进制(H). 数制中用少量数码按次序排列成数位,并按由低到高的进位方式进行计 数。(数码的个数称为基数) D---0,1,2,3,4,5,6,7,8,9------数码十个(基为10)-------…

Linux中的二进制可执行文件和脚本可执行文件及Shebang

Linux中的二进制可执行文件和脚本可执行文件及Shebang 二进制可执行文件 我们知道&#xff0c;一个C程序经过预处理、编译、汇编、链接就会得到一个二进制可执行文件&#xff0c;这种文件在Linux中叫做ELF文件。比如我们有一个C源代码hello.c&#xff1a; #include <stdi…