前言
本章开始进行内存方面内容的讲解,本章主要讲解是如何划分与组织内存的。
1.分段还是分页来划分内存?
从内存管理角度分析
第一点,从表示方式和状态确定角度考虑。 段的长度大小不一,用什么数据结构表示一个段,如何确定一个段已经分配还是空闲呢?而页的大小固定,我们只需用位图就能表示页的分配与释放。
比方说,位图中第 1 位为 1,表示第一个页已经分配;位图中第 2 位为 0,表示第二个页是空闲,每个页的开始地址和大小都是固定的。
第二点,从内存碎片的利用看。 由于段的长度大小不一,更容易产生内存碎片。段与段之间存在着不大不小的空闲空间,内存总的空闲空间很多,但是放不下一个新段。
而页的大小固定,分配最小单位是页,页也会产生碎片,比如我需要请求分配 4 个页,但在内存中从第 1~3 个页是空闲的,第 4 个页是分配出去了,第 5 个页是空闲的。这种情况下,我们通过修改页表的方式,就能让连续的虚拟页面映射到非连续的物理页面。
第三点,从内存和硬盘的数据交换效率考虑, 当内存不足时,操作系统希望把内存中的一部分数据写回硬盘,来释放内存。这就涉及到内存和硬盘交换数据,交换单位是段还是页?
如果是段的话,其大小不一,A 段有 50MB,B 段有 1KB,A、B 段写回硬盘的时间也不同,有的段需要时间长,有的段需要时间短,硬盘的空间分配也会有上面第二点同样的问题,这样会导致系统性能抖动。如果每次交换一个页,则没有这些问题。
还有最后一点,段最大的问题是使得虚拟内存地址空间,难于实施。
综上,我们自然选择分页模式来管理内存,其实现在所有的商用操作系统都使用了分页模式管理内存。我们用 4KB 作为页大小,这也正好对应 x86 CPU 长模式下 MMU 4KB 的分页方式。
2.如何表示一个页?
首先是把物理内存空间分成 4KB 大小页,这页表示从地址 x 开始到 x+0xFFF 这一段的物理内存空间,x 必须是 0x1000 对齐的。这一段 x+0xFFF 的内存空间,称为内存页。
真正的物理内存空间布局信息来源于 e820map_t 结构数组,之前的初始化中,我们已经将其转换成 phymmarge_t 结构数组了,由 kmachbsp->mb_e820expadr 指向。
3.如何具体表示一个页?
我们需要页的状态、页的地址、页的分配记数、页的类型、页的链表,你自然就会想到,这些信息可以用一个 C 语言结构体封装起来。
//内存空间地址描述符标志
typedef struct s_MSADFLGS
{
u32_t mf_olkty:2; //挂入链表的类型
u32_t mf_lstty