在Linux操作系统中,CPU在执行一个进程的时候,都会访问内存。但CPU并不是直接访问物理内存地址,而是通过虚拟地址空间来间接的访问物理内存地址。

一、关于虚拟地址空间的介绍

所谓地址空间,是地址访问可以达到的所有地址的集合,而不是支持这个地址空间的全部硬件。就好比邮政编码是6位,它的地址空间就是10610^6106个地址,从0到999999。但不表示你需要有这么多个建筑区支持它。32位进程可以发出2322^{32}232个地址,比如*ptr=0xNNNNNNN,这个被访问的地址不一定有内存存在,只是说它可以发出这个地址而已。而这个地址对应什么物理内存,这是操作系统给的,给了就有,没给就没有。

1.1 物理地址和物理内存

物理内存是真实的可见的物理存储器件,就像下面所画的一样,硬件电路通过总线能够一次查找到对应存储单元的值,物理上是高低点位,对应0/1表示。

如下图所示,A2就是第一排第二个存储单元,那么A2就是它的物理地址。假如你的电脑上插了一个8GB的内存条,对应的就有8GB,也就是8589934592个内存单元。再假如现在你的电脑是32位的系统,那么cpu能寻找到每一个内存单元吗?如果能寻找到,那么对于32位操作系统最大的寻址能力是多少呢?对于64位的系统来说呢?这个问题下面解答。

1.2 内存寻址

假定没有内存管理单元(MMU)的支持下,对于32位操作系统而言,你给到CPU的地址是32位的,也就是一个long型的数据,所以最大的寻址能力就是2322^32232,也就是4 GB。所以,对于32位系统而言,你插个8 GB内存是有一半的空间,系统是没法寻找到的,等于浪费。而对于64位系统来说,寻址能力理论上可以达到2642^64264,但是,处理器所支持的RAM大小地址总线上的管脚限制,早期的Intel处理器只能支持4 GB寻址,从奔腾pro开始才出现了物理地址扩展的机制来支持更大内存空间,所以如果没有这个机制,或者这个机制被关闭,对于手机来说经常如此,那么内存寻址仍然只有4 GB。但是,现代计算机都是会存在MMU的,这是一个硬件电路,能够将一个逻辑地址转换成一个线性地址,也就是虚拟地址。

1.3 逻辑地址和线性地址

逻辑地址,就是指机器语言指令中用来指定一个操作数或一条指令的地址,由一个段(segment)和偏移量(offset)组成,说地直白点就是CPU拿到的地址。

线性地址,也就是虚拟地址,是一个32位无符号的整型数,所以虚拟地址空间总共就是4 GB大小。

系统中的每个进程所使用的地址就是线性地址或者说虚拟地址,而不是什么逻辑地址,更不是物理地址,所以对每个独立的进程来说,线性空间大小是4 GB是没有错的,且其中0-1GB的地址空间给予内核访问,其它3GB由每个进程自己访问。

虽然每个进程拥有4G的虚拟地址空间,但显然在它运行的每个小段时间内,它需要访问的都是少量的空间,并且这些空间一般都是地址连续的。如果真的给这个进程分配全部的物理内存,那绝大多数物理内存就浪费了。所以现在一般采用分页的技术(将虚拟地址空间和物理内存划分成固定大小的小块),建立页表,把进程的虚拟地址空间页映射到物理内存的页帧上。这里页表保存的就是映射关系。然后随着进程的运行,就会按需分配页,那些长时间未使用的页帧又会被操作系统回收。(虚拟地址与物理地址的映射,比如将0x123456 映射到 0x345678,这个0x123456就是所谓的虚拟地址,但是这个数字并不需要存,而是该进程运行后产生的一个虚拟地址,真正需要存的是页表,也就是说页表是实实在在占空间的,虚拟地址并不占空间)

那是不是说一个进程就只能访问4GB的物理内存大小呢?答案是否定的,具体访问到哪个物理地址要看MMU将线性地址转换后的物理地址才能知道,所以有可能两个进程的地址同时访问同一个物理地址,这在物理地址很小的情况下是经常会发生的事情。当然,同一时刻,一个物理内存单元只可能由某个进程来访问,至于具体原理,这个MMU来实现的,这里不细讲。

1.4 地址转换

有了MMU,CPU拿到的逻辑地址就可以经过它来找到对应的物理地址了。

MMU有两个硬件电路单元,一个称之为分段单元(segmentation unit)、一个称之为分页单元(paging unit),下面是它的工作原理:

逻辑地址→分段单元→线性地址→分页单元→物理地址逻辑地址\to分段单元\to线性地址\to分页单元\to物理地址逻辑地址→分段单元→线性地址→分页单元→物理地址

所以,如果系统、CPU、MMU和内存坐在一起,那肯定会发生下面的对话:

系统:CPU我给你个逻辑地址0xff84ed43,你去找到这个人

CPU: 好的系统,我去问问MMU。 MMU,我这里有个地址0xff84ed43,你帮忙找一下

MMU: 好的,请求分段单元,这个地址你先找到他家所在街道的地址

分段单元:报告,已经找到了他家所在的街道地址,地址是0x56ac21fe

MMU:好的,请求分页单元,这个是他家的街道地址,你找到他家住几号。

分页单元:报告,已经找到了,他家具体地址是0x12345678

CPU:谢谢,我这就去找他

如何理解虚拟地址空间

二、页表

通常将虚拟地址空间以512Byte ~ 8K,作为一个单位,称为页,并从0开始依次对每一个页编号。这个大小通常被称为页面

将物理地址按照同样的大小,作为一个单位,称为框或者块,也从0开始依次对每一个框编号。

操作系统通过维护一张表,这张表上记录了每一对页和框的映射关系,如下图所示:

这张表就称为页表。

在windows系统下,页面为4k,这里我们以4k为例。
一个4G虚拟地址空间,将会产生1024*1024个页,页表的每一项存储一个页和一个框的映射,所以,至少需要1M个页表项。如果一个页表项大小为1Byte,则至少需要1M的空间,所以页表被放在物理内存中,由操作系统维护。
当CPU要访问一个虚拟地址空间对应的物理内存地址时,先将具体的虚拟地址A/页面大小4K,结果的商作为页表号,结果的余作为页内地址偏移。

例如:
CPU访问的虚拟地址:A
页面:L
页表号:(A/L)
页内偏移:(A%L)

CPU中有一个页表寄存器,里面存放着当前进程页表的起始地址和页表长度。将上述计算的页表号和页表长度进行对比,确认在页表范围内,然后将页表号和页表项长度相乘,得到目标页相对于页表基地址的偏移量,最后加上页表基地址偏移量就可以访问到相对应的框了,CPU拿到框的起始地址之后,再把页内偏移地址加上,访问到最终的目标地址。如图:

注意,每个进程都有页表,页表起始地址和页表长度的信息在进程不被CPU执行的时候,存放在其PCB内。

按照上述的过程,可以发现,CPU对内存的一次访问动作需要访问两次物理内存才能达到目的,第一次,拿到框的起始地址,第二次,访问最终物理地址。CPU的效率变成了50%。为了提高CPU对内存的访问效率,在CPU第一次访问内存之前,加了一个快速缓冲区寄存器,它里面存放了近期访问过的页表项。当CPU发起一次访问时,先到TLB中查询是否存在对应的页表项,如果有就直接返回了。整个过程只需要访问一次内存。如图:

这种方式极大的提高了CPU对内存的访问效率。将近90%。
然而这样的方式还是存在弊端,在物理内存中需要拿出至少1M的连续的内存空间来存放页表。可以通过多级页表的方式,将页表分为多个部分,分别存放,这样就不要求连续的整段内存,只需要多个连续的小段内存即可。
把连续的页表拆分成多个页表称之为一级页表,再创建一张页表,这张页表记录每一张一级页表的起始地址并按照顺序为其填写页表号。
通过这样的方式,CPU从基地址寄存器中拿到了一级页表的地址,从地址结构中取出一级页表的页表号,找到二级页表的起始物理地址;然后结合地址结构中的中间10位(二级页表上的页表号),可以找到对应的框的起始地址,最后结合页内偏移量,就可以计算出最终目标的物理地址。如图:

三、页目录表和页表的关系


上图反应了如下信息:

  • 进程的 4G 线性空间 被划分成 三个部分 : 进程空间 (0-3G)、 内核直接映射空间 (3G– high_memory)、 内核动态映射空间 (VMALLOC_START - VMALLOC_END)
  • 三个空间使用同一张页目录表 ,通过 CR3 可找到此页目录表 。但不同的空间在页目录表中页对应不同的项,因此互相不冲突
  • 内核初始化以后,根据实际物理内存的大小,计算出 high_memory、VMALLOC_START、VMALLOC_END 的值。并为“内核直接映射”空间建立好映射关系,所有的物理内存都可以通过此空间进行访问。
  • “进程空间”和“内核动态映射空间”的映射关系是动态建立的(通过缺页异常)

假设在有三个线性地址 addr1, addr2, addr3 ,分别属于三个线性空间不同部分(0-3G、3G-high_memory、vmalloc_start-vmalloc_end),但是最终都映射到物理页面1:

  1. 三个地址对应不同的页表和页表项
  2. 但是页表项的高20bit肯定是1,表示物理页面的索引号是1
  3. 同时,根据高20bit,可以从 mem_map[]中找到对应的struct page结构, struct page 用于管理实际的物理页面(就是实际物理页面的物理地址了,到这里就不绕弯子了,顺便想到高速缓冲的匹配命中操作是用哈希表,换算出的要访问的实际物理地址拿到哈希表的输入计算一下哈希值,看看有没命中)
  4. 从线性地址最终的,根据页目录表,页表,可以找到物理地址
  5. struct page和物理地址之间很容易互相转换
  6. 从物理地址,可以很容易的反推出在内核直接映射空间的线性地址(蓝线)。要想得到在进程空间或者内核动态映射空间的对应的线性地址,则需要遍历相应的“虚存区间”链表。

关于页目录表:

  1. 每个进程有一个属于自己的页目录表,可通过 CR3 寄存器找到
  2. 而内核也有一个独立于其它进程的页目录表,保存在 swapper_pg_dir[] 数组中
  3. 当进程切换的时候,只需要将新进程的页目录把地址加载到 CR3 寄存器中即可
  4. 创建一个新进程的时候,需要为它分配一个 page,作为页目录表,并将swapper_pg_dir[] 的高256项拷贝过来,低768项则清0

Linux-页、页表、页框(块)+虚拟内存相关推荐

  1. 段、页、页框、页表、页表项

    段.页.页框.页表.页表项 分页式虚拟内存: 页.页框.页表.页表项 段页式虚拟内存(分段+分页): 段.段表.段表项.页.页框.页表.页表项 分页式虚拟内存: 页.页框.页表.页表项 页:进程中的块 ...

  2. linux 内存管理---页框回收(十)

    为什么需要页回收? linux的设计哲学之一:尽可能多的使用内存,比如尽可能的多使用memory cache,disk cache,因为这在系统负载比较小时,能够提升系统性能,但是随着cache越来越 ...

  3. 【内存】Linux 页表、大页与透明大页|大页内存

    目录 页表与MMU CPU访问的是什么地址(虚拟地址,物理地址)? MMU如何工作 MMU对内存的保护 多级页表 一. 内存映射与页表 1. 内存映射 2. 页表 4. 页表的简单工作原理 大页 什么 ...

  4. 扇区、磁盘块、页、页框、缓冲区之间的关系!

    扇区.磁盘块.页.页框.缓冲区之间的关系! 扇区是块设备传输数据的基本单元,也就是说它是块设备中最小的寻址单位,扇区通常的大小为512B. 块是内核对文件系统的一种抽象,也就是说内核执行的所有磁盘操作 ...

  5. Linux 透明大页 THP 和标准大页 HP

    作者 | JiekeXu 来源 |公众号 JiekeXu DBA之路(ID: JiekeXu_IT) 大家好,我是JiekeXu,很高兴又和大家见面了,今天和大家一起来看看 Linux 透明大页 TH ...

  6. Linux内存 匿名页,学点linux之四:内存

    内存也是一大块 第二天·内存 分页机制 缓冲区溢出攻击,注意rw权限保护 用户态不能访问内存态,inter,amd的漏洞,meltdown,从用户空间偷取了内核空间数据,熔断漏洞 内存分zone DM ...

  7. 存储器Flash页、扇区、块的区别

    关注+星标公众号,不错过精彩内容 作者 | strongerHuang 微信公众号 | 嵌入式专栏 大家都知道Flash是用于存储数据的存储器,但很多读者看到页(Page).扇区(Sector).块( ...

  8. linux 内存大页,Linux大页内存管理等---菜鸟初学

    1. 查看linux的内存情况: free -m 2. 查看是否开启大页的方法: cat /proc/meminfo |grep -i HugePage AnonHugePages: 276480 k ...

  9. 刷脏页策略linux,【随笔】Linux刷脏页

    一.脏页的由来 前情摘要: 1. 在多级存储系统中,上一级高速设备会成为下一级低速设备的缓存.相较之内存,磁盘是一个低速设备,因此Linux中会通过一种叫"磁盘高速缓存"的软件机制 ...

  10. dataTables去掉搜索框,每页多少条框体,解决Cannot reinitialise DataTable问题,以及数据格式ajax等问题...

    1.关于datatables配置 function dosearch(){ $('#example').DataTable({ "searching": false, //去掉搜索 ...

最新文章

  1. nginx telnet sshd
  2. 干货丨深度学习和经典机器学习的全方位对比
  3. ERP系统管理员的工具箱 推荐几款优秀的数据比较同步工具 Data Compare and Sync tool...
  4. leetcode精选
  5. 怎么强制限制div宽度
  6. 简单理解js闭包、类型引用....第一章
  7. 计算机编程术语. dsp,什么是数字信号处理器(DSP)
  8. 洛谷P1157----组合数的输出
  9. Java剪切板操作大全
  10. 教你从零搭建Web漏洞靶场OWASP Benchmark
  11. Xamarin开发Android时Visual Studio 2012没有智能提示解决办法
  12. 微软 .NET 团队宣布 Visual Basic 停止更新,VB 编程即将谢幕
  13. 在中国从事什么职业最赚钱_中国最好的十大职业2(转)
  14. 《从技术走向管理》读后感
  15. usb3.0速度测试软件,USB3.0传输速度测试 揭秘速度到底是多少
  16. Word中规范输入大写的中文日期(转)
  17. 用完加速器国内的网址打不开了?
  18. http basic认证
  19. 智慧灯杆智能网关喷雾降尘系统
  20. QtCreator中Kits选项变灰,有感叹号

热门文章

  1. 计算机专业必懂知识,学习计算机知识必须懂得50个专业术语
  2. php数据库密码查询,php数据库查询及密码匹配的功能
  3. mysql replace into +1_mysql replace into用法详细说明
  4. 自定义 Behavior - 仿新浪微博发现页的实现
  5. Android View框架总结(五)View布局流程之Layout
  6. matlab 最优化编程,Matlab最优化编程例子
  7. 汇编64位无法生成可用exe_MASM学习x86汇编语言2 寄存器、伪指令与程序调试
  8. centos6.5 安装mysql5.6_centos6.5 安装mysql5.6
  9. pythonATM,购物车项目实战_补充6-lib模块
  10. C# internal和public