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#/ 背景 — 机制与策略分离 机制:一个通用的、可定制…

局域网中计算机网络密码查看,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…

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

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

(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)-------…

pe能用的固态硬盘测试软件,通用pe工具箱教你如何让硬盘4K对齐

昨天小编教大家如何查看电脑硬盘是否4K对齐,马上就有读者告诉小编,查看电脑硬盘是否4K对齐的方法学到了,那么我使用的固态硬盘如何做到4K对齐呢?问的好啊!现如今用户对电脑硬件的要求是越来越高。很多用户都不仅仅满足…

[2020-ECCV]PIPAL-a Large-Scale Image Quality Assessment Dataset for Perceptual Image Restoration论文简析

[2020-ECCV] PIPAL: a Large-Scale Image Quality Assessment Dataset for Perceptual Image Restoration 论文简析 论文:https://arxiv.org/abs/2007.12142 代码及数据集:https://github.com/HaomingCai/PIPAL-dataset 概述 本文认为随着图像重建&…

郫都区计算机老师周俊老师,教师节,带你走进郫都教师背后的故事

点击“郫都教育”关注我们:)有这样一群人“师者,所以传道,授业,解惑也”是他们奉献一生的事业“随风潜入夜,润物细无声”是他们培养英才的责任“春蚕到死丝方尽,蜡炬成灰泪始干”是他们追求终生的信仰值此第…

(2021) 18 [代码讲解] 可执行文件

(2021) 18 [代码讲解] 可执行文件 南京大学操作系统课蒋炎岩老师网络课程笔记。 视频:https://www.bilibili.com/video/BV1HN41197Ko?p18 讲义:http://jyywiki.cn/OS/2021/slides/C8.slides#/ 背景 回顾 程序 状态机 状态机执行 状态机上的路径状…

如何学习计算机思维,刘康平:为什么我们每个人都应该学习计算思维?

不久前,微软亚洲研究院资深学术合作经理刘康平应邀在“造就”做了演讲,以下为演讲节选,由“造就”授权转载。刘康平 微软亚洲研究院资深学术合作经理以中国象棋为例,在这样一个棋局上,你怎么用最快的方式找到「将」和「…

链接与加载-NJU-JYY

(2021) 19 [代码讲解] 从零实现动态加载 南京大学操作系统课蒋炎岩老师网络课程笔记。 视频:https://www.bilibili.com/video/BV1N741177F5?p15 讲义:http://jyywiki.cn/OS/2021/slides/C9.slides#/ 背景 回顾: ELF可执行文件 只要能完成…