mirror of
https://github.com/CyC2018/Interview-Notebook.git
synced 2026-10-29 15:13:44 +00:00
Update 计算机操作系统 - 内存管理.md
重新绘制配图。
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 130 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 141 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 113 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 149 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 220 KiB |
+17
-15
@@ -18,13 +18,13 @@
|
||||
|
||||
## 虚拟内存
|
||||
|
||||
虚拟内存的目的是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。
|
||||
虚拟内存的目的是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。此外,每个进程都有独立的地址空间,一个进程无法直接访问另一个进程的内存,操作系统还可以按页设置读写和执行权限。
|
||||
|
||||
为了更好的管理内存,操作系统将内存抽象成地址空间。每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中。当程序引用到不在物理内存中的页时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。
|
||||
为了更好的管理内存,操作系统将内存抽象成地址空间。每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中。当程序引用到不在物理内存中的页时,硬件触发缺页中断,由操作系统将缺失的页装入物理内存,再重新执行失败的指令。
|
||||
|
||||
从上面的描述中可以看出,虚拟内存允许程序不用将地址空间中的每一页都映射到物理内存,也就是说一个程序不需要全部调入内存就可以运行,这使得有限的内存运行大程序成为可能。例如有一台计算机可以产生 16 位地址,那么一个程序的地址空间范围是 0\~64K。该计算机只有 32KB 的物理内存,虚拟内存技术允许该计算机运行一个 64K 大小的程序。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7b281b1e-0595-402b-ae35-8c91084c33c1.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/vm-mapping.png" width="640px"/> </div><br>
|
||||
|
||||
## 分页系统地址映射
|
||||
|
||||
@@ -32,9 +32,13 @@
|
||||
|
||||
一个虚拟地址分成两个部分,一部分存储页面号,一部分存储偏移量。
|
||||
|
||||
下图的页表存放着 16 个页,这 16 个页需要用 4 个比特位来进行索引定位。例如对于虚拟地址(0010 000000000100),前 4 位是存储页面号 2,读取表项内容为(110 1),页表项最后一位表示是否存在于内存中,1 表示存在。后 12 位存储偏移量。这个页对应的页框的地址为 (110 000000000100)。
|
||||
下图的页表存放着 16 个页,这 16 个页需要用 4 个比特位来进行索引定位。例如对于虚拟地址 0x3ABC(0011 101010111100),前 4 位是页面号 3,读取表项内容为(101 1),页表项最后一位表示是否存在于内存中,1 表示存在。后 12 位是偏移量,直接拼接到页框号 101 后面,得到物理地址 0x5ABC(101 101010111100)。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/cf4386a1-58c9-4eca-a17f-e12b1e9770eb.png" width="500"/> </div><br>
|
||||
<div align="center"> <img src="pics/page-translate.png" width="720px"/> </div><br>
|
||||
|
||||
页表存放在内存中,每次访问内存之前都要先查一次页表。CPU 中的快表(Translation Lookaside Buffer, TLB)缓存最近用过的页表项,命中时不用再访问页表。
|
||||
|
||||
64 位系统的地址空间很大,如果用一张页表覆盖全部地址,页表本身就会非常大,因此使用多级页表,只为用到的地址分配下一级页表。例如 x86-64 通常使用 4 级页表,48 位虚拟地址分为 4 个 9 位的页表索引和 12 位的页内偏移。
|
||||
|
||||
## 页面置换算法
|
||||
|
||||
@@ -54,7 +58,7 @@
|
||||
|
||||
举例:一个系统为某进程分配了三个物理块,并有如下页面引用序列:
|
||||
|
||||
```html
|
||||
```text
|
||||
7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1
|
||||
```
|
||||
|
||||
@@ -70,11 +74,11 @@
|
||||
|
||||
因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。
|
||||
|
||||
```html
|
||||
```text
|
||||
4,7,0,7,1,0,1,2,1,2,6
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/eb859228-c0f2-4bce-910d-d9f76929352b.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/lru-stack.png" width="720px"/> </div><br>
|
||||
|
||||
### 3. 最近未使用
|
||||
|
||||
@@ -105,7 +109,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
|
||||
|
||||
当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候,检查最老页面的 R 位。如果 R 位是 0,那么这个页面既老又没有被使用,可以立刻置换掉;如果是 1,就将 R 位清 0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ecf8ad5d-5403-48b9-b6e7-f2e20ffe8fca.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/second-chance.png" width="720px"/> </div><br>
|
||||
|
||||
### 6. 时钟
|
||||
|
||||
@@ -113,19 +117,17 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问
|
||||
|
||||
第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面连接起来,再使用一个指针指向最老的页面。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/5f5ef0b6-98ea-497c-a007-f6c55288eab1.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/clock.png" width="720px"/> </div><br>
|
||||
|
||||
## 分段
|
||||
|
||||
虚拟内存采用的是分页技术,也就是将地址空间划分成固定大小的页,每一页再与内存进行映射。
|
||||
|
||||
下图为一个编译器在编译过程中建立的多个表,有 4 个表是动态增长的,如果使用分页系统的一维地址空间,动态增长的特点会导致覆盖问题的出现。
|
||||
例如一个程序有代码、全局数据、堆和栈几部分,其中堆和栈会动态增长。如果放在一维的地址空间中,就要预先给每一部分留出位置,某一部分增长到相邻部分的位置时就会发生覆盖。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/22de0538-7c6e-4365-bd3b-8ce3c5900216.png"/> </div><br>
|
||||
分段的做法是把每一部分作为一个段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。地址由段号和段内偏移组成,通过段表找到段的基址,再加上偏移得到物理地址。
|
||||
|
||||
分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。
|
||||
|
||||
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e0900bb2-220a-43b7-9aa9-1d5cd55ff56e.png"/> </div><br>
|
||||
<div align="center"> <img src="pics/segments.png" width="740px"/> </div><br>
|
||||
|
||||
## 段页式
|
||||
|
||||
|
||||
Reference in New Issue
Block a user