目录

文章目录

  • 目录
  • 前文列表
  • 物理地址与虚拟地址
  • 内存空间的组织方式
  • 虚拟地址空间的编址
    • 内核态地址空间
    • 用户态地址空间
  • 内-外存空间的交换与虚拟存储空间之间的映射关系
    • 缺页异常

前文列表

《Linux 操作系统原理 — 内存 — 物理存储器与虚拟存储器》

物理地址与虚拟地址

物理地址:即物理主存的地址空间。主存被组织成一个由 M 个连续的、字节大小相同的单元组成的数组,每字节都有一个唯一的物理地址(Physical Address,PA)。第一个字节的地址为 0,接下来的字节的地址为 1,依此类推。给定这种简单的结构,CPU 访问存储器的最自然的方式就是使用物理地址,即物理寻址。

虚拟地址:即虚拟存储地址空间,它能够让用户态应用程序以为自己拥有一块连续可用的 “物理” 地址,但实际上从程序视角所见的都是虚拟地址,而且这些虚拟地址对应的物理主存空间通常可能是碎片的,甚至有部分数据还可能会被暂时储存在外部磁盘设备上,在需要时才进行数据交换。

虚拟存储器为了实现虚拟地址空间的 隔离性连续性,就必须满足以下条件:

  1. 新的 内存组织 方式。
  2. 新的 虚拟地址空间编址 方式。
  3. 新的 内存分配 方式。
  4. 新的 物理地址和虚拟地址的转换 方式。

内存空间的组织方式

为了让数据得以在内存和外存之前高速交换,也为了让虚拟地址和物理地址之间可以进行高效转换。若使用传统的字节流方式进行内-外存是数据传输,总线的传输速率和磁盘的读写速率必然会成为瓶颈。因此,虚拟存储器需要实现特殊的内存组织方式来满足以上两点需求。

虚拟内存管理方式可以简单分为连续分配管理方式和非连续分配管理方式这两种:

  • 连续分配管理方式:为一个用户程序分配一个连续的内存空间,常见的如块式管理。
  • 非连续分配管理方式:允许一个用户程序使用的内存,分布在离散的内存空间中,常见的如页式管理、段式管理,以及综合了两者优点的段页式管理。

从物理地址和虚拟地址的特征可以看出,虚拟存储器地址映射的实现是建立在离散分配的内存管理方式的基础之上的

  • 块式管理 (远古时代的计算机操系统的内存管理方式,暂且不暂开):将内存分为几个固定大小的块,每个块中只包含一个进程。如果程序运行需要内存的话,操作系统就分配给它一块,如果程序运行只需要很小的空间的话,分配的这块内存很大一部分几乎被浪费了。这些在每个块中未被利用的空间,称之为碎片。

  • 页式管理 :把内存分为大小相等且固定的一页一页的形式,页较小,相对相比于块式管理的划分力度更大,提高了内存利用率,减少了碎片。页式管理通过页表对应逻辑地址和物理地址

  • 段式管理:页式管理虽然提高了内存利用率,但是页式管理其中的页对于用户程序而言并无实际意义。段式管理则是把内存分为多个段,每段的空间要比一页的空间大些。但最重要的是段对于用户程序而言是有实际意义的,每个段定义了一组逻辑信息,例如:有主程序段 main、子程序段 X、数据段 D 及栈段 S 等。段式管理通过段表对应逻辑地址和物理地址

  • 段页式管理:结合了段式管理和页式管理的优点。先将用户程序分成若干个段,再把每个段分成若干个页,并为每一个段赋予一个段名。如此的,段页式管理机制中段与段之间以及段的内部的都是离散的。

详见《Linux 操作系统原理 — 内存 — 页式管理、段式管理与段页式管理》

虚拟地址空间的编址

在 32 位 CPU 中,Linux 上的虚拟地址空间为 4G。在 64 位 CPU 中的虚拟地址空间为 16G。在 64 位的很多应用场景中,实际的物理内存可能远远小于虚拟内存的大小。所以这里以 32 位举例,Linux 会为每个进程维护一个单独的虚拟地址空间。

  • 0~3G 用户态地址空间:是某个进程独有的,进程之间互相隔离。
  • 3~4G 内核态地址空间:所有的进程,以及内核态线程都会共享这部分地址空间。

所以,我们习惯的将 Linux 虚拟存储器系统分为 内核虚拟存储器进程虚拟存储器。则虚拟地址空间又可以分为 内核地址空间用户地址空间

内核态地址空间

内核态地址空间包含了内核的代码和数据结构,其中的某些区域被映射到给所有进程共享的物理内存页面存储所有进程共享的内核代码和全局数据结构;其他区域则包含每个进程都不相同的数据。例如:用户进程页表、内核在进程的上下文中执行代码时使用的栈(Stack),以及记录虚拟地址空间当前组织的各种数据结构。

  • 直接映射区:线性空间中从 3G 开始最大 896M 的区间,为直接内存映射区。
  • 动态内存映射区:该区域由内核函数 vmalloc 来分配。
  • 持久映射区:该区域和 4G 的顶端只有 4k 的隔离带,其每个地址项都服务于特定的用途,如:ACPI_BASE 等。
  • 永久内核映射区:该区域可访问高端内存。

用户态地址空间

  • stack:用户进程栈。
  • mmap 共享库映射区:共享库及匿名文件的映射区域。
  • heap 运行时堆:在程序运行过程中使用 malloc() 申请的内存区域。
  • .bss 段:存放程序中未初始化的全局变量。
  • .data 数据段:存放程序中已经初始化的全局变量。
  • .text 代码段:存放可执行代码、字符串字面值、只读变量。

C 语言程序中的变量在用户地址空间中有四个区域可以存放:

·执行用户进程时,需要先从内存中读取该进程的指令,然后执行,获取指令时用到的就是虚拟地址。这个虚拟地址是程序链接时确定的(内核加载并初始化进程时会调整动态库的地址范围)。为了获取到实际的数据,CPU 需要将虚拟地址转换成物理地址。

由于每个进程都有 3G 的用户态地址空间,所以操作系统的物理内存无法对这些地址空间进行一一映射。因此 Linux kernel 需要一种机制,把进程的用户态地址空间映射到物理内存上。当一个用户进程请求访问物理内存时,内核通过存储在内核态地址空间中的进程页表(Page Table),把这个虚拟地址映射到物理地址。最基本的映射单位是页(Page),对应为页面上的是页表项(PTE)。

页表是由内核维护的,里面的每个内存映射(Memory Mapping)都将一块虚拟地址映射到一个特定的物理地址空间(物理内存或者磁盘存储空间)。每个进程拥有自己的页表,和其他进程的页表没有关系,以此实现了用户程序间虚拟空间的隔离。

另外,值得注意的是,在每个进程创建加载时,内核只是为进程 “创建” 了虚拟内存的布局(e.g. 初始化进程控制表中内存相关的链表),实际上并不立即就把虚拟内存对应位置的程序数据和代码(e.g. .text、.data 段)拷贝到物理内存中,只是建立好虚拟内存和磁盘文件之间的映射(叫做存储器映射)。等到运行到对应的程序时,才会通过缺页异常,来拷贝数据到内存空间。还有进程运行过程中,要动态分配内存,比如:malloc 时也只是分配了虚拟内存,即为这块虚拟内存对应的页表项做相应设置,当进程真正访问到此数据时,才引发缺页异常,继而写入数据。

用户进程申请并访问物理内存(或磁盘存储空间)的过程如下

  1. 用户进程向操作系统发出内存申请请求。
  2. 系统会检查进程的虚拟地址空间是否被用完,如果有剩余,给进程分配虚拟地址。
  3. 系统为这块虚拟地址创建内存映射(Memory Mapping),并将它放进该进程的页表(Page Table)。
  4. 系统返回虚拟地址给用户进程,用户进程开始访问该虚拟地址。
  5. CPU 根据虚拟地址在此进程的页表(Page Table)中找到了相应的内存映射(Memory Mapping),但是这个内存映射(Memory Mapping)没有和物理内存关联,于是产生缺页中断。
  6. 操作系统收到缺页中断后,分配真正的物理内存并将它关联到页表相应的内存映射(Memory Mapping)。中断处理完成后,CPU 就可以访问内存了
  7. 当然缺页中断不是每次都会发生,只有系统觉得有必要延迟分配内存的时候才用的着,也即很多时候在上面的第 3 步系统会分配真正的物理内存并和内存映射(Memory Mapping)进行关联。

内-外存空间的交换与虚拟存储空间之间的映射关系

我们可以简易的认为虚拟空间都被映射到了磁盘空间中(事实上这种映射是按需的,通过 mmap 函数),并且由页表记录映射位置,当访问到某个地址的时候,通过页表中的有效位,可以得知此数据是否在内存中,如果不是,则通过缺页异常,将磁盘对应的数据拷贝到内存中,如果没有空闲内存,则选择牺牲页面,替换其他页面。

mmap 是用来建立从虚拟空间到磁盘空间的映射的,可以将一个虚拟空间地址映射到一个磁盘文件上,当不设置这个地址时,则由系统自动设置,函数返回对应的虚拟内存地址,当访问这个地址的时候,就需要把磁盘上的内容拷贝到内存了,然后就可以读或者写,最后通过 man_map 可以将内存上的数据换回到磁盘,也就是解除虚拟空间和内存空间的映射,这也是一种读写磁盘文件的方法,也是一种进程共享数据的方法,即共享内存。

缺页异常

  • 通过 get_free_pages 申请一个或多个物理页面。
  • 换算 addr 在进程 pdg 映射中所在的 pte 地址。
  • 将 addr 对应的 pte 设置为物理页面的首地址。
  • 系统调用:Brk—申请内存小于等于 128kb,do_map—申请内存大于 128kb。

Linux 操作系统原理 — 内存 — 基于 MMU 硬件单元的虚/实地址映射技术相关推荐

  1. Linux 操作系统原理 — 内存 — 基于局部性原理实现的内/外存交换技术

    目录 文章目录 目录 前文列表 基于局部性原理实现的内-外存交换技术 局部性原理 Swap 交换分区 前文列表 <Linux 操作系统原理 - 内存 - 物理存储器与虚拟存储器> < ...

  2. Linux 操作系统原理 — 内存 — 内存分配算法

    目录 文章目录 目录 前文列表 内存碎片 伙伴(Buddy)分配算法 Slab 算法 虚拟内存的分配 内核态内存分配 vmalloc 函数 kmalloc 用户态内存分配 malloc 申请内存 用户 ...

  3. Linux 操作系统原理 — 内存 — 页式管理、段式管理与段页式管理

    目录 文章目录 目录 前文列表 页式管理 快表 多级页表 基于页表的虚实地址转换原理 应用 TLB 快表提升虚实地址转换速度 页式虚拟存储器工作的全过程 缺页中断 为什么 Linux 默认页大小是 4 ...

  4. Linux 操作系统原理 — 内存 — 物理存储器与虚拟存储器

    目录 文章目录 目录 Linux 内存管理全貌 物理存储器 虚拟存储器 Linux 内存管理全貌 物理存储器 见<计算机组成原理 - 存储系统>. 虚拟存储器 在早期的计算机系统中,程序员 ...

  5. Linux 操作系统原理 — 内存管理 — 虚拟地址空间

    目录 文章目录 目录 虚拟内存技术 页式内存管理技术 虚拟地址格式与页表(32bit 系统) 虚拟地址格式与页表(64bit 系统) CPU MMU 虚实地址转换 TLS 快表转换 虚拟地址空间与 C ...

  6. Linux 操作系统原理 — 内存 — Cache 和 Buffer

    目录 文章目录 目录 无处不在的 Cache Cache 和 Buffer 的区别在哪里? 为什么需要缓存? Linux 的缓存机制 Page Cache 的同步机制(一致性问题) 无处不在的 Cac ...

  7. Linux 操作系统原理 — 内存管理 — 页式内存管理技术

    目录 文章目录 目录 虚拟内存技术 页式内存管理技术 虚拟内存技术 虚拟内存技术是操作系统实现的一种高效的物理内存管理方式,具有以下作用: 使得进程间彼此隔离:通过将物理内存和虚拟地址空间联系起来,并 ...

  8. Linux 操作系统原理 — 内存 — mmap 进程虚拟内存映射

    目录 文章目录 目录 mmap() mmap 与 read/write 的性能比较 mmap 优点总结 mmap() mmap() 是一个系统调用函数,本质是一种进程虚拟内存的映射方法,可以将一个文件 ...

  9. linux的原理和运用,Linux操作系统原理与应用_内存寻址

    原标题:Linux操作系统原理与应用_内存寻址 第五讲今天上线啦. 在本次课程中,陈老师详细的讲解了有关于内存寻址的演变的相关知识. 第一部分中,介绍了关于内存寻址的相关背景知识.内存寻址-操作系统设 ...

最新文章

  1. VB.NET通讯录源代码
  2. 统一建模语言(UML) 版本 2.0
  3. leetcode304. 二维区域和检索 - 矩阵不可变
  4. nginx 一个请求发给多台机器_一个机器人可以同时为多台数控机床上下料吗?东智力衡...
  5. 怎么让电脑屏幕一直亮着_电脑屏幕总是闪烁?试试这个方法
  6. 最新性能测试:Kafka、Pulsar 和 Pravega 哪个最强?
  7. mask rcnn属于dnn么_基于OpenCV DNN的 MaskRCNN 目标检测与实例分割
  8. 计算机三级之嵌入式系统学习笔记3
  9. BeanFactory和FactoryBean
  10. html缩放排版乱了_交作业 | 代码排版逐行显现效果
  11. TOMCAT下载及配置
  12. User-Agent的变迁——浏览器大战之前世今生
  13. java程序往微信群里发消息_通过java程序,给微信发送消息
  14. 846计算机类,x846-《计算机类学科基础》考试内容及范围(8页)-原创力文档
  15. Oracle dba_users视图
  16. 星星之火OIer:总分题解
  17. Redis锁解决超卖问题
  18. coolnbsp;sensor/image/videonbsp;technbsp;cou…
  19. python lamba表达式
  20. 虚拟专题:联邦学习 | 联邦学习研究综述

热门文章

  1. linux oracle em使用,案例:五步解决linux操作系统Oracle EM乱码的问题
  2. html css 表格自动高度,html – 表格单元格(IE)中的Textarea CSS {height:100%}
  3. TensorFlow 人脸识别实验 ImportError: No module named 'sklearn.model_selection'
  4. 推荐7本EEG领域值得阅读的书籍
  5. eeglab中文教程系列(8)-选择数据的epochs并进行比较
  6. 撬开骁龙8一看,满满都是顶会论文
  7. 飙着车学「机器学习」?要不是380万人围观我都不敢相信
  8. B站焊武帝爆火出圈:纯手工拼晶体管自制CPU,耗时半年,可跑程序
  9. 人脸识别走光引热议!原来后台能看到的不只有脸,网友已社死,审核辣哭眼...
  10. 华人计算机大牛刘炯朗教授仙逝,他是姚期智院士的博士导师,还著有离散数学教科书...