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 都将其充份利用,将 ...
随机推荐
- LOJ #2718. 「NOI2018」归程(Dijkstra + Kruskal重构树 + 倍增)
题意 给你一个无向图,其中每条边有两个值 \(l, a\) 代表一条边的长度和海拔. 其中有 \(q\) 次询问(强制在线),每次询问给你两个参数 \(v, p\) ,表示在 \(v\) 出发,能开车 ...
- Leetcode 344.反转字符串 By Python
请编写一个函数,其功能是将输入的字符串反转过来. 示例: 输入:s = "hello" 返回:"olleh" 思路 Python里面的切片用来解决这个问题就很快 ...
- 沉迷Link-Cut tree无法自拔之:[BZOJ2594][Wc2006]水管局长数据加强版
来自蒟蒻 \(Hero \_of \_Someone\) 的 \(LCT\) 学习笔记 $ $ 这应该算是道套路题吧, 如果将图中的边转换成点, 再将边权变点权, 就可以用 \(LCT\) 来维护了 ...
- 【BZOJ2425】[HAOI2010]计数(组合数学)
[BZOJ2425][HAOI2010]计数(组合数学) 题面 BZOJ 洛谷 题解 很容易的一道题目. 统计一下每个数位出现的次数,然后从前往后依次枚举每一位,表示前面都已经卡在了范围内,从这一位开 ...
- 【AGC005F】简单的问题 Many Easy Problems
Description 链接 Solution 对于每个\(k\),统计任选\(k\)个点作为关键点的"最小生成树"的大小之和 正向想法是枚举或者计算大小为\(x\).叶子数目为\ ...
- yum 安装Mysql
RHEL6.5-MySql-yum安装登录 客户端工具的使用mysql:Linux下提供了一个访问mysql服务器的客户端工具—mysql,其由mysql软件包提供,除了这些工具之外还有一些图形化界面 ...
- [学习笔记]prufer序列
前言 PKUWC和NOIWC都考察了prufer序列,结果统统爆零 prufer序列就是有标号生成树对序列的映射 prufer序列生成 每次选择编号最小的叶子删掉,把叶子的父亲加入prufer序列,直 ...
- 应用程序发生异常 unknown software exception (0xc00000fd)... - 栈溢出(Stack overflow)
今天在写程序的时候,弹出这样的提示对话框: 应用程序发生异常 unknown software exception (0xc00000fd): 相关代码是这样,在一个函数中读取一个csv文件,先根据这 ...
- c语言输入字符注意
1.c=getchar(); //getchar can't accept Space Tab 2. scanf("%c",&c); printf(" ...
- Win7任务栏合并
在“任务栏” -> "任务栏按钮" -> "始终合并.隐藏标签” 另外,如果想使时间显示详细,可消去“使用小图标”





