本文已参与「新人创作礼」活动,一起开启掘金创作之路。
虚拟内存
操作系统引入了虚拟内存,进程持有的虚拟地址会通过 CPU 芯片中的内存管理单元(MMU)的映射关系,来转换变成物理地址,然后再通过物理地址访问内存
有两种映射方式:
- 内存分段
- 内存分页
内存分段
于是程序可由若干个逻辑分段组成的,如可由代码分段、数据分段、栈段、堆段组成。不同的段是有不同的属性的,所以就用分段(Segmentation)的形式把这些段分离出来。
因为分段后各段是离散的,为了保证程序能正常运行,就必须能从物理内存中找到各个逻辑段的存放位置,实现这个功能的是段表
段表
- 段表里面保存的是这个段的基地址
- 如果段内偏移量是合法的,就将段基地址加上段内偏移量得到物理内存地址。
分段的办法很好,优点是解决了程序本身不需要关心具体的物理内存地址的问题,但它缺点是:
- 第一个就是外部 内存碎片的问题。
- 第二个就是内存交换的效率低的问题。(硬盘的读写速度比内存慢太多了,每一次内存交换,我们都需要把一大段连续的内存数据写到硬盘上。 )
内存分页
分页是把整个虚拟和物理内存空间切成一段段固定尺寸的大小。这样一个连续并且尺寸固定的内存空间,我们叫页(Page)。在 Linux 下,每一页的大小为 4KB。为什么要分页?为了更合理的分配进程在内存中存放
虚拟地址与物理地址之间通过页表来映射
寻址过程:
- 简单来说就是:重定位寄存器(保存着该模块的物理地址)+ 目标的逻辑地址
分页的优势:
采用了分页,那么释放的内存都是以页为单位释放的,也就不会产生无法给进程使用的小内存。
如果内存空间不够,操作系统会把其他正在运行的进程中的「最近没被使用」的内存页面给释放掉,也就是暂时写在硬盘上,称为换出(Swap Out)。
一旦需要的时候,再加载进来,称为换入(Swap In)。所以,一次性写入磁盘的也只有少数的一个页或者几个页(不会出现一整个段的磁盘读写),不会花太多时间,内存交换的效率就相对比较高。
这种简单的页表有空间上的缺陷,页表必须连续存放,当页表过大时,需要占用很多连续的页框。