前言
我在阅读 “小林coding” 公众号的图解操作系统系列文章后感觉受益良多,因此进行一些小总结,方便日后查阅。本篇是针对几种不同方式的内存管理进行的总结。
原文链接:真棒! 20 张图揭开内存管理的迷雾,瞬间豁然开朗
内存管理是将虚拟内存映射到物理内存的方式,常见类型包括分段管理、分页管理和段页式管理。
一、分段管理
OS为每一个进程分配一个连续的物理地址空间,这个空间即为一个段。进程中使用的是虚拟地址,在虚拟地址中有该进程的段号和段内偏移量,通过段表查询段号对应段的起始物理地址以及段的最大长度。根据起始地址和偏移量就可以找到每个虚拟地址对应的物理地址。
这种管理方式会造成空间的浪费(即产生空间碎片),进而导致频繁的内存与硬盘之间的数据交换。
二、分页管理
1.一级分页
分页管理有效弥补了分段管理的缺点,将可操作的最小地址空间记为页,一页对应4KB的内存空间。在为进程分配内存空间时,以页为单位分配,这样不容易产生空间碎片,进而减少了内存和硬盘间的交换频率,提高了效率。
在分页管理中使用页表来维护逻辑地址到物理地址的映射。虚拟地址中包含了(虚拟)页号和页内偏移量。
页表项中包括每一页在进程中的虚拟页号和其对应在物理内存上的基地址。
MMU:内存管理单元,用来找到虚拟地址对应的物理地址的计算机硬件。
但是分页管理的缺点也很明显,对于每个进程我们都需要维护这样一张页表,而一张页表所占用的空间也比较多,在32位的环境下,每个进程分配的虚拟内存有4GB,那么它的页表大小就是4MB,当有多个进程在运行时,页表所需要的存储空间就变大了,这很浪费内存资源。
2.多级分页
为了减小页表占用的空间,提出分级页表,对全部的页进行分级管理。以二级页表为例,在32位系统中,一级页表项有1024个,一级页表中的每项又对应了一个二级页表,这个二级页表中又有1024个页表项,因此综合起来就能覆盖全部的页表项。
在进程中,实际占用的页并不多,因此系统只会创建进程中使用到的一级页表项对应的二级页表,其他的二级页表不会被创建,这样就减少了页表的占用空间。二级页表可以推广到多级页表,进一步减少页表占用空间。
一般而言,被使用的页表会放在内存中,未被使用的页表则先放在磁盘上,当需要使用时再从磁盘调到内存中。
3.TLB
为了提高寻找对应地址的效率,将一些进程中常用的页表项在一个缓存器中缓存起来,这个缓存器称为TLB(页表缓存),它和MMU一起被封装在CPU芯片中。CPU 在寻址时,会先查 TLB,如果没找到,才会继续查常规的页表。
三、段页式管理
这是一种将分段管理和分页管理相结合的内存管理方式,对于每个进程都有一个段表,段表中每一项对应了一个页表,(段表项中记录的是对应页表的基地址);每个页表项中则对应了页的物理内存基地址。因此虚拟地址包括了段号、页号和页内偏移。
段页式管理看起来和二级页表很像啊==
四、Intel处理器中的内存管理
Intel处理器在设计时同时使用段式管理和页式管理,先使用段号和段内偏移量经过段式内存管理器获得一个线性地址,(此时的段号和段内偏移量称为逻辑地址,是进程中使用的),再在一个页表上由该线性地址找到对应的页物理起始地址。
注意这和段页式管理不同,此时找到对应的物理地址需要的是段号+段内偏移量,但是在段页式管理中需要的是段号+页号+页内偏移量。
在Linux系统中,想要屏蔽掉这个段内MMU,减少地址对应的时间,因此会将进程的段号都设为0,只使用偏移量,此时的偏移量直接是线性地址,不需要MMU转换了。
总结
这应该是内存管理入门级的介绍,如有理解错误,欢迎指出!
任重而道远呐~