虚拟地址空间
进程地址空间由进程可寻址的虚拟内存组成,内核允许进程使用这种虚拟内存的地址。每个进程都有一个 32位或64位 的平坦地址空间,空间的大小取决于体系结构。(平坦指的是地址空间范围是一个独立的连续空间)
一些操作系统提供了段地址空间,这种地址空间并非是一个独立的线性区域,而是被分段的,但现代 采用虚拟内存的操作系统通常都是用平坦地址空间。
通常情况下,每个进程都有唯一的这种平坦地址空间。一个进程的地址空间与另一个进程的地址空间即使有相同的内存地址,实际上也彼此互不相干,我们称这样的进程为线程。
内存地址是一个给定的值,它要在地址空间范围之内,这个值表示32位地址空间中的一个特定的字节。32位系统下,一个进程可以寻址 4GB (即232)的虚拟内存。通过内核,进程可以给自己的地址空间动态地添加或减少内存区域。
进程只能访问有效区域内的内存地址。 每个内存区域也具有相关权限如对相关进程有可读、可写、可执行属性。如果一个进程访问了不在有效范围中的内存区域,或以不正确的方式访问了有效地址,那么内核就会终止该进程,并返回 “段错误” 信息。
进程地址空间中的任何有效地址都只能位于唯一的区域,这些内存区域不能相互覆盖。
页表
当用程序访问一个虚拟地址时,首先必须将虚拟地址转换成物理地址,然后处理器才能解析地址访问请求。地址的转换工作需要通过查询页表完成。
概括的讲,地址转换需要将虚拟地址分段,使每段虚拟地址都作为一个索引指向页表,而页表项则指向下一级别的页表或者指向最终的物理界面。
Linux中使用三级页表完成地址转换。利用多级页表能够节约地址转换所需要占用的存放空间。Linux对所有体系结构,包括那些不支持三级页表的体系结构 都使用三级页表管理 ,因为使用三级页表结构可以利用 “最大公约数” 的思想—一种设计简单的体系结构,可以按照需要在编译时简化使用页表的三级结构,比如只是用两级。
- *目录是页全局目录(PGD),它包含了一个 pgd_t 类型数组,多数体系结构中 pgd_t 类型等同于无符号长整型类型。PGD中的表项指向二级页目录中的表项 :PMD
- 二级页表是中间页目录(PMD),它是个 pmd_t 类型数组,其中的表项指向 PTE 中的表项
- 最后一级的页表 简称 页表,其中包含了pte_t 类型的页表项,该页表项指向物理页面。
每个进程都有自己的页表(当然,线程会共享页表)。内存描述符的 pgd 域指向的就是进程的页全局目录。
由于几乎每次对虚拟内存中的页面访问都必须先解析它,从而得到物理内存中的对应地址,所以页表操作的性能非常关键。因此多数体系结构都实现了一个翻译后缓冲器 TLB,TLB 作为一个将虚拟地址映射到物理地址的硬件缓存,当请求访问一个虚拟地址时,处理器将首先检查 TLB 是否缓存了该虚拟地址到物理地址的映射,如果缓存命中,物理地址立刻返回;否则就需要再通过页表搜索需要的物理地址。