【Linux】再谈虚拟地址空间

简介: 【Linux】再谈虚拟地址空间

一、页表难道真的只是简单一 一存储映射吗?


我们知道虚拟地址空间的基本单位是字节,所以在32位平台下虚拟地址空间上会有多少个地址呢?

答案是:2 32 2^{32}232个!虚拟地址空间中的每一个地址依次为 [ 0 , 2 32 − 1 ] [ 0 , 2 ^{32} − 1 ][0,2321] 即 0x00000000 - 0xFFFFFFFF,也就是我们常说的 4 GB 虚拟内存空间。

为了让虚拟地址与物理地址能够一 一映射,我们需要有页表来维护映射关系,为了后续方便维护页表我们先来计算一下页表的大小:虚拟地址4个字节,物理地址4字节,假设其他属性4字节,虚拟地址总数2 32 2^{32}232个。

2 32 ∗ ( 4 + 4 + 4 ) b y t e = 50 , 331 , 648 K B = 49 , 152 M B = 48 G B > 4 G B 2^{32} * (4 + 4 + 4) byte = 50,331,648KB = 49,152MB = 48GB > 4GB232(4+4+4)byte=50,331,648KB=49,152MB=48GB>4GB

经过计算我们发现如果我们要维护页表,我们需要有48GB的内存,但是在32位平台下我们的CPU最多只能控制4GB的内存,这说明页表绝对不是简单的一 一存储映射!

为了搞清楚页表的存储和映射规则我们还要了解文件系统方面的知识,如果你没有这方面的知识的话可以先看这里的的一些介绍《【Linux】文件系统


二、内存与磁盘IO时是逐个字节进行IO吗?


由于磁盘在存储时是按照数据块的方式进行存储的所以注定了文件在磁盘的时候,就是以块为单位进行存储的(一个块的大小一般是4KB即8个扇区的大小,其具体大小OS有关)

所以OS在和磁盘这样的设备进行IO交互的时候,就不能按照字节为单位的而是要按照为单位。

  1. 其实如果非要OS在和磁盘这样的设备进行IO交互的时候设定单位为字节也是可以的,但是这回导致过多的IO,过多的IO注定了过多的寻址,过多的寻址意味着过多的机械运动 ,由于磁盘本身就是一个机械设备效率低下,过多的IO会导致效率更加低下。
  2. 如果将IO的单位设定的过大,又会导致磁盘不能被有效的利用,而且数据加载不是IO单位的整倍数时会迁移更多的无关数据。

为了让内存与与磁盘更高效地进行IO,操作系统对内存也进行了按管理划分,OS将内存划分成一个个页框,其中每个页框可以存储的数据的大小为4KB,这4KB被称为一页 (Page)的数据。

为了管理内存的每个页框Linux系统中有一种数据结构struct page,由于struct page结构本身就占有一定内存,如果struct page结构设计过大,那么本身就会占用较多内存,而给系统或者用户可用的内存就较少,所以strcut page对结构大小非常敏感,即使增加一个字节对系统影响也会非常大,故Linux社区对struct page的结构做了严格设计,不会轻易增加字段。

page结构中有一个非常重要的字段叫flag通过这个字段可以判断当前内存块有没有被占用,最后Linux使用数组将所有的page管理起来struct page mm[1,048,576]

内存管理的本质:将磁盘中的特定的4KB的数据块(数据内容)放入到哪一个物理内存的页框中(数据保存的空间)


局部性原理的特性的一些理解

根据局部性原理,我们允许计算机提前加载正在访问的数据的相邻或者附近的数据,通过预先加载要访问数据的附近的数据可以减少未来的IO次数。

假设我们使用一个10KB的文件,那么我们需要加载3个数据块,意味着我们使用该文件时在内存中会多加载数据,这部分多加载出来的数据的本质就叫:做数据的预加载! 所以我们没有必要花费心思去处理多加载进内存的数据。


三、页表的存储和转化原理


以32位操作系统为例,虚拟地址其实并不是被整体使用的,而是按照 10 + 10 + 12 10 + 10 + 1210+10+12的方式进行划分使用的。页表也不仅仅只有一个而是多个而且是分级别的。

虚拟地址的前10位被存放进入页目录里面,再向后10位被存放进页表项里面,经过页目录可以找到页表项,经过页表项可以找到物理内存中的页框的起始地址,页框的起始地址 + 虚拟地址最低12位的比特位既可以找到真正的物理地址

最低12位比特位可以表示的数据范围是:[ 0 , 4095 ] [0, 4095][0,4095],而页框内的可用地址总数为:4096 40964096(4KB) ,于是通过页框起始地址 + 页内偏移就可以访问到一个页框内的所有地址,所有页框按照同样的操作便能找到所有的地址,这种寻址方式被称为:基地址+偏移量的方式。

这时我们再计算一下页目录的大小:页目录总数为1,目录里面的行数:2 10 2^{10}210 ,假设虚拟地址前10个比特位存储需要4个字节,指向页表项的指针也是4字节。

1 ∗ 2 10 ∗ ( 4 + 4 ) b y t e = 8 K B 1*2^{10}* (4 + 4) byte= 8KB1210(4+4)byte=8KB

这时我们再进行计算页表项的大小:页表项总数为2 10 2^{10}210,目录里面的行数:2 10 2^{10}210 ,假设虚拟地址再向后10个比特位存储需要4个字节,指向页框的指针也是4字节。

2 10 ∗ 2 10 ∗ ( 4 + 4 ) b y t e = 8 M B 2^{10} * 2^{10}* (4 + 4) byte= 8MB210210(4+4)byte=8MB

所以我们使用8MB的空间就能完成映射功能!

最后页表并不是直接全部创建的,而是根据需要进行创建多少页表,如果页表不够再进行新增。


我们实际在申请malloc内存的时候,OS只要给你在虚拟地址空间上申请就行了,当你在真正访问时,0S发现虚拟地址并没没有真正建立映射,于是触发缺页中断,执行中断处理方法才会自动给你申请具体的物理内存并且填充页表。

四、补充


此外页表的属性是有很多的,例如是否命中,读写权限,内核级/用户级权限等,这些权限也是相当有用的信息。

例如:修改常量字符串为什么会触发段错误?

答案是:指针变量里面保存的是指向的字符的虚拟起始地址,指针变量寻址的时候,必定会伴随虚拟到物理的转化,通过MMU + 查页表的方式 ,对你的操作进行权限审查,发现你虽然能找到,但是你进行的操作是非法的,MMU发生异常,OS识别异常,异常转换成信号,发送给目标进程,进程在从内核转换成为用户态的时候,进行信号处理,然后终止进程。

我们讲解原理采用的是32位操作系统进行讲解的,对于64位操作系统也是同理,64位平台下用的是多级页表来进行更多地址的映射

相关文章
|
15天前
|
关系型数据库 MySQL Unix
linux优化空间&完全卸载mysql——centos7.9
linux优化空间&完全卸载mysql——centos7.9
52 7
|
1月前
|
安全 Linux 虚拟化
网络名称空间在Linux虚拟化技术中的位置
网络名称空间(Network Namespaces)是Linux内核特性之一,提供了隔离网络环境的能力,使得每个网络名称空间都拥有独立的网络设备、IP地址、路由表、端口号范围以及iptables规则等。这一特性在Linux虚拟化技术中占据了核心位置🌟,它不仅为构建轻量级虚拟化解决方案(如容器📦)提供了基础支持,也在传统的虚拟机技术中发挥作用,实现资源隔离和网络虚拟化。
网络名称空间在Linux虚拟化技术中的位置
|
1月前
|
安全 Linux 网络虚拟化
Linux网络名称空间和Veth虚拟设备的关系
在讨论Linux网络名称空间和veth(虚拟以太网对)之间的关系时,我们必须从Linux网络虚拟化的核心概念开始。Linux网络名称空间和veth是Linux网络虚拟化和容器化技术的重要组成部分,它们之间的关系密不可分,对于构建隔离、高效的网络环境至关重要。😊
|
1天前
|
存储 算法 Linux
【Linux】线程的内核级理解&&详谈页表以及虚拟地址到物理地址之间的转化
【Linux】线程的内核级理解&&详谈页表以及虚拟地址到物理地址之间的转化
|
1天前
|
存储 安全 Linux
Linux:进程地址空间
Linux:进程地址空间
20 10
|
9天前
|
存储 缓存 监控
|
9天前
|
存储 Linux 程序员
【Linux-14】进程地址空间&虚拟空间&页表——原理&知识点详解
【Linux-14】进程地址空间&虚拟空间&页表——原理&知识点详解
|
18天前
|
安全 Linux 编译器
【linux进程(七)】程序地址空间深度剖析
【linux进程(七)】程序地址空间深度剖析
|
18天前
|
Shell Linux 程序员
【linux进程(六)】环境变量再理解&程序地址空间初认识
【linux进程(六)】环境变量再理解&程序地址空间初认识
|
19天前
|
存储 Linux 调度
Linux的学习之路:12、地址空间(续)与进程的创建、终止和等待
Linux的学习之路:12、地址空间(续)与进程的创建、终止和等待
20 0