Linux内存管理3---分页机制
1.前言
本文所述关于内存管理的系列文章主要是对陈莉君老师所讲述的内存管理知识讲座的整理。
本讲座主要分三个主题展开对内存管理进行讲解:内存管理的硬件基础、虚拟地址空间的管理、物理地址空间的管理.
本文将主要以X86架构为例来介绍Linux内存管理的分页机制。
2.分页机制
- 页(Page)
将线性地址空间划分成若干大小相等的片,称为页
- 页框(Page Frame)
物理地址空间划分成与页大小相等的若干存储块,称为页框

图 线性地址空间与物理地址空间的映射
上图说明线性地址空间是连续的(如程序经过编译链接后是连续的线性地址),而物理地址空间可能是不连续的。
- 页表
页表是把线性地址映射到物理地址的一种数据结构
- 页表项内容
1.物理页面的起始地址;
2.该页的属性,表示页的特性,比如该页是否在内存,是否可以被读出或写入,具体的属性位如下:
(1) 第0位是P(Present),如果P=1,表示页装入到内存中,如果P=0,表示不在内存中。
(2) 第1位是R/W(Read/Write),第2位是U/S(User/Supervisor)位,这两位为页表或页提供硬件保护。
(3) 第3位是PWT(PageWrite-Through)位,表示是否采用写透方式,写透方式就是既写内存(RAM)也写高速缓存,该位为1表示采用写透方式
(4) 第4位是PCD(PageCache Disable)位,表示是否启用高速缓存,该位为1表示启用高速缓存。
(5) 第5位是访问位,当对相应的物理页面进行访问时,该位置1。
(6) 第7位是PageSize标志,只适用于页目录项。如果置为1,页目录项指的是4MB的页
(7) 第9~11位由操作系统专用,Linux也没有做特殊之用。
- 两级页表
图 两级页表
所谓两级页表就是对页表再进行分页。第一级称为页目录,其中存放的是关于页表的信息,第二级称为页表
页目录的起始地址存放在CR3中的高20位,因此跟踪一个进程的时候,拿到CR3就等于拿到了进程的根:-D
线性地址的最高10位(即22位~ 31位)用来产生第一级的索引,线性地址的中间10位(即21位~12位)对物理页面进行索引,最低12位表示页内偏量
举例:4MB的页表按二级页表再次分页(4MB/4K)可以分为1K个页,同样对每个页的描述需要4个字节,于是可以算出页目录最多占用4KB个字节,正好是一个页
页目录共有1K个表项,于是,线性地址的最高10位(即22位~ 31位)用来产生第一级的索引。
两级表结构的第二级称为页表,每个页表也刚好存放在一个4K字节的页中,包含1K个表项,第二级页表由线性地址的中间10位(即21位~12位)进行索引
最低12位表示页内偏量。
- 线性地址结构
图 线性地址结构
如上结构对应的伪代码:
图 线性地址结构对应的伪代码
- 页表项结构
图 页表项结构
页目录和页表中的页表项结构都相同,都占用4个字节的长度
- 硬件保护机制
(1)内核态或用户态对页面的访问权限
对于页表,页的保护是通过页表项的U/S标志和R/W标志来控制的,U/S为0,只有处于内核态的操作系统才能对此页或页表进行寻址,否则内核态和用户态均可寻址
(2)对页可读或可写
如果R/W为0,说明相应的页表或页是只读的,否则是可读写的
- 线性地址到物理地址的转换
图 线性地址到物理地址的转换过程
(1)用32位线性地址的最高10位第31~22位作为页目录项的索引,将它乘以4,与CR3中的页目录的起始地址相加,获得相应目录项在内存的地址。
(2)从这个地址开始读取32位页目录项,取出其高20位,再给低12位补0,形成的32位就是页表在内存的起始地址。
(3)用32位线性地址中的第21~12位作为页表中页表项的索引,将它乘以4,与页表的起始地址相加,获得相应页表项在内存的地址。
(4)从这个地址开始读取32位页表项,取出其高20位,再将线性地址的第11~0位放在低12位,形成最终32位页面物理地址。
3. 分页示例
- 假如操作系统给一个正在运行的进程分配的线性地址为:0x2000000~0x2003ffff,这个空间由64页组成
如上进程地址范围最高10位为页目录域0x80,指向进程页目录的128项,如果没有给这个进程分配其它的线性地址,则进程页目录表的其它1023项为0,
也就是这个进程在进程页目录表中只占用一项

图 只有一个目录项的页目录表和页表
- 假设进程需要读取线性地址为0x20021406中的内容,这个地址由分页机制如何处理?
中间10位的值(即页表域的值)范围从0到0x03f,或十进制的从0到63。因而只有页表的前64个表项是有意义的,其余960表项填为0。
假设进程需要读线性地址0x20021406中的内容。这个地址由分页机制按下面的方法进行处理:
1.目录域的0x80用于选择页目录的第0x80目录项,此目录项指向页表。
2.页表域的第0x21项用于选择页表的第0x21表项,此表项指向页所对应的内存物理页面。
3.最后,偏移量0x406用于在目标物理页面中读偏移量为0x406中的字节。
注:如果页表第0x21表项的Present标志为0,说明此页还没有装入内存中;在这种情况下,分页机制在转换线性地址的同时产生一个缺页异常(参见内存管理一章)。
无论何时,当进程试图访问限定在0x20000000到0x2003ffff范围之外的线性地址时,都将产生一个缺页异常,因为这些页表项都填充了0,尤其是,它们的Present标志都为0。
4.页面高速缓存

图 页面高速缓存的作用
由于在分页情况下,页表是放在内存中的,这使CPU在每次存取一个数据时,都要至少两次访问内存,从而大大降低了访问速度
为了提高速度,在IA32中设置一个最近存取页的高速缓存硬件机制,它自动保持32项处理器最近使用的页表项,因此,可以覆盖128K字节的内存地址。
当访问线性地址空间的某个地址时,先检查对应的页表项是否在高速缓存中,如果在,就不必经过两级访问了,如果不在,再进行两级访问
平均来说,页面高速缓存大约有90%的命中率,也就是说每次访问存储器时,只有10%的情况必须访问两级分页机构。这就大大加快了速度,有些书上也把页面高速缓存叫做“联想存储器”或“转换旁视缓冲器(TLB)”。
5. Linux中的分页
- Linux主要通过分页机制来实现虚拟存储器管理
原因如下:
Linux分段机制使得所有进程都使用相同的段寄存器值,所有进程使用相同的进程地址空间(0~4G)
Linux设计目标之一就是能够移植到大多数流行的处理器平台,但很多RISC处理器平台对分段机制支持有限
- 为了保持可移植性,Linux采用三级分页模式而不是两级

图 LInux三级分页模式
注:尽管Linux采用的是三级分页模式,但我们的讨论还是以IA32的两级分页模式为主,因此,Linux忽略中间目录层
6.参考文献
[1] Linux内存管理讲座PPT-陈莉君
Linux内存管理3---分页机制的更多相关文章
- Linux内存寻址之分页机制
在上一篇文章Linux内存寻址之分段机制中,我们了解逻辑地址通过分段机制转换为线性地址的过程.下面,我们就来看看更加重要和复杂的分页机制. 分页机制在段机制之后进行,以完成线性—物理地址的转换过程.段 ...
- [转帖]Linux分页机制之概述--Linux内存管理(六)
Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...
- Linux内存管理2---段机制
1.前言 本文所述关于内存管理的系列文章主要是对陈莉君老师所讲述的内存管理知识讲座的整理. 本讲座主要分三个主题展开对内存管理进行讲解:内存管理的硬件基础.虚拟地址空间的管理.物理地址空间的管理. 本 ...
- 深入理解 Linux 内存管理
1. 内存地址 以Intel的中央处理器为例,Linux 32位的系统中.物理内存的基本单位是字节(Byte),1个字节有8个二进制位. 每一个内存地址指向一个字节,内存地址加1后得到下一个字节的地址 ...
- [转帖]Linux分页机制之分页机制的演变--Linux内存管理(七)
Linux分页机制之分页机制的演变--Linux内存管理(七) 2016年09月01日 20:01:31 JeanCheng 阅读数:4543 https://blog.csdn.net/gatiem ...
- Linux内存管理解析(一) : 分段与分页机制
背景 : 在此文章里会从分页分段机制去解析Linux内存管理系统如何工作的,由于Linux内存管理过于复杂而本人能力有限.会尽量将自己总结归纳的部分写清晰. 从实模式到保护模式的寻址方式的不同 : 1 ...
- 浅谈Linux内存管理机制
经常遇到一些刚接触Linux的新手会问内存占用怎么那么多?在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,在这 ...
- 了解linux内存管理机制(转)
今天了解了下linux内存管理机制,在这里记录下,原文在这里http://ixdba.blog.51cto.com/2895551/541355 根据自己的理解画了张图: 下面是转载的内容: 一 物理 ...
- 【转载】Linux 内存管理机制
在Linux中经常发现空闲内存很少,似乎所有的内存都被系统占用了,表面感觉是内存不够用了,其实不然.这是Linux内存管理的一个优秀特性,主要特点是,无论物理内存有多大,Linux 都将其充份利用,将 ...
随机推荐
- 切割模型固定写死了切平面方程是y=0.1
上一篇讲到3d模型切割我遇到的问题(切面的纹理会混乱),经过这段时间的琢磨,有了解决方案,当然我这里只给出我的解决思路,投入到实际项目中还需要做许多工作,比如我在上一篇中切割模型固定写死了切平面方程是 ...
- 自学Linux Shell4.1-监测程序ps top kill
点击返回 自学Linux命令行与Shell脚本之路 4.1-监测程序ps top kill 1. PS命令 linux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的 ...
- 【Luogu4921】情侣?给我烧了!(组合计数)
[Luogu4921]情侣?给我烧了!(组合计数) 题面 洛谷 题解 很有意思的一道题目. 直接容斥?怎么样都要一个平方复杂度了. 既然是恰好\(k\)对,那么我们直接来做: 首先枚举\(k\)对人出 ...
- 【BZOJ2003】[HNOI2010]矩阵(搜索)
[BZOJ2003][HNOI2010]矩阵(搜索) 题面 懒得粘了,不难找吧. 题解 看的学长写的题解,也懒得写了 大概是这样的. 不难发现只需要确定第一行和第一列就能确定答案,而确定第一行之后每确 ...
- 设置outlook 2013 默认的ost路径
How To Change Default Data File (.OST) Location in Office 2013 To set the default location of an out ...
- LoadRunner回放乱码
乱码的原因和服务器字符集编码相关,默认LR是gbk解码,如果服务器是utf8,那么需要改为utf8解码,这样中文就显示正常了. 通过查看源码,可以知道服务器的编码方式:<meta charset ...
- 最长上升子序列LIS(51nod1134)
1134 最长递增子序列 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递 ...
- EFCodeFirst快速搭建入门
EFCodeFirst快速搭建入门 1.新建Model类库项目. 添加EntityFramework.dll的引用. 编写实体类Course,Student. namespace EFCodeFirs ...
- bracketed-paste-magic:zle:41: not enough arguments for -U
原因是zsh的插件出问题了,解法方法如下: 把 ~/.oh-my-zsh/lib/misc.zsh 文件中的第一段 if 注释掉 OK 啦 # ]]; then # for d in $fpath; ...
- CodeForces834D DP + 线段树
http://codeforces.com/problemset/problem/834/D 将一个长度为n的序列分为k段 使得总价值最大一段区间的价值表示为区间内不同数字的个数 n<=3500 ...





