linux规划进程空间使用分段的方法,我们来试试分段
分段机制下的虚拟地址由两部分组成,段选择子和段内偏移量。段选择子就保存在前面讲过的段寄存器里面。段选择子里面最重要的是段号,用作段表的索引。段表里面保存的是这个段的基地址、段的界限和特权等级等。虚拟地址中的段内偏移量应该位于 0 和段界限之间。如果段内偏移量是合法的,就将段基地址加上段内偏移量得到物理内存地址。
例如,我们将上面的虚拟空间分成以下 4 个段,用 0~3 来编号。每个段在段表中有一个项,在物理空间中,段的排列如下图的右边所示。
在 Linux 里面,段表全称段描述符表(segment descriptors),放在全局描述符表 GDT(Global Descriptor Table)里面,会有下面的宏来初始化段描述符表里面的表项。
c#define GDT_ENTRY_INIT(flags, base, limit) \
{ \
.limit0 = (u16) (limit), \
.limit1 = ((limit) >> 16) & 0x0F, \
.base0 = (u16) (base), \
.base1 = ((base) >> 16) & 0xFF, \
.base2 = ((base) >> 24) & 0xFF, \
.type = (flags & 0x0f), \
.s = (flags >> 4) & 0x01, \
.dpl = (flags >> 5) & 0x03, \
.p = (flags >> 7) & 0x01, \
.avl = (flags >> 12) & 0x01, \
.l = (flags >> 13) & 0x01, \
.d = (flags >> 14) & 0x01, \
.g = (flags >> 15) & 0x01, \
}
通过分析,我们发现,所有的段的起始地址都是一样的,都是 0。这算哪门子分段嘛!所以,在 Linux 操作系统中,并没有使用到全部的分段功能。那分段是不是完全没有用处呢?分段可以做权限审核,例如用户态 DPL 是 3,内核态 DPL 是 0。当用户态试图访问内核态的时候,会因为权限不足而报错。
其实 Linux 倾向于另外一种从虚拟地址到物理地址的转换方式,称为分页(Paging)。
Linux的页表机制是虚拟内存管理的核心部分,它负责将虚拟地址转换为物理地址。下面将详细介绍Linux的页表机制。
一、概述 Linux使用了分页机制来管理虚拟内存,将虚拟地址空间划分为固定大小的页,通常为4KB。每个进程都有自己的页表,用于将虚拟地址映射到物理地址。
对于物理内存,操作系统把它分成一块一块大小相同的页,这样更方便管理,例如有的内存页面长时间不用了,可以暂时写到硬盘上,称为换出。一旦需要的时候,再加载进来,叫作换入。这样可以扩大可用物理内存的大小,提高物理内存的利用率。
二、页表结构 Linux的页表结构是多级的,通常包括页目录、页表和页三个级别。每个级别都有一个对应的页表项,用于存储地址映射信息。
三、地址转换过程
当一个进程访问虚拟地址时,Linux的页表机制会进行地址转换,将虚拟地址转换为物理地址。转换过程如下:
四、页表的优化 为了提高页表的访问效率,Linux采用了一些优化技术,包括:
五、总结
Linux的页表机制是虚拟内存管理的核心,通过多级页表结构和优化技术,实现了高效的地址转换和内存管理。
Learn more:
本文作者:yowayimono
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!