目录
地址转换
分段机制
分页机制
保护机制
任务之间的保护
内存段和寄存器的特殊保护
首页 运维 nginx Linux 保护模式下的内存管理

Linux 保护模式下的内存管理

Jul 06, 2023 pm 03:20 PM
linux 模式 保护

我们知道,内存可以看做一个非常大的数组,我们想要查找内存中某个元素的话,会通过数组的下标来指定,内存也是如此,不过这有一个前提是这个数组是由一组有序的字节组成的,在这个有序的字节数组中,每个字节都有一个唯一的地址,这个地址也叫做内存地址。

内存中存储着很多对象,每个对象是由不同字节组成的,比如一个 char 对象,一个 byte 对象,一个 int 对象等等,它们都分部在内存的各个位置中,CPU 对内存中这些对象的地址进行定位的操作就叫做内存寻址。内存总线宽度决定了可以寻址多少位的内存地址,从地址0开始计算。由于 80X86 是 32 位的,所以总线宽度也是 32 位,因此一共有 2 ^ 32 个内存地址,所以总共可以存放 4GB 的内存地址。可以通过连续的内存地址来提取多个字节的数据类型,比如 int、long、double。

虽然能够寻址到对象,但是这些对象存放的字节顺序是不同的,这里分为两种存放方式,即大端法和小端法。

比如现在有一个 int 类型的对象,位于地址 0x100 处,它的十六进制数值是 0x01234567,我给你画一幅图你就明白这两个存放顺序的区别了。

Linux 保护模式下的内存管理

这个其实很好理解,0x01234567 的 int 数据类型可以拆分为 01 23 45 67 个字节,并且 01 是高位,67 是低位,于是可以解释小端法和大端法的存储顺序:即小端法是低位在前,而大端法是高位在前。大端法和小端法只是存储顺序的区别,和对象的位数、数值无关。大多数 Intel 机器都采用的是小端模式,所以 80X86 也是小端存储,而一些 IBM 和 Oracle 的大多数机器都是使用的大端存储方式。

由于计算机是无法直接将内存中的数据一次性全部寻址完毕,因为它相对实在太过庞大,所以内存一般会进行分段,这里就涉及一个疑问:即内存为什么要分段。我上面只是笼统的介绍了下。

内存为什么要分段?

https://www.php.cn/link/d005ce7aeef46bd18515f783fb8e87fa

使用分段机制,内存空间被划分为线性区域,每个线性区域可以通过段基址加上段内偏移来定位。段基址部分由 16 位的段选择符来指定,其中 14 位是可以选择 2 ^ 14 次方即 16384 个段,段内偏移地址部分使用 32 位的值来指定,因此段内地址可以是 0 - 4G ,一个段的最大长度是 4 GB,这也就和上面所说的 4 GB 的内存地址相呼应。由 16 位段和 32 位段内偏移构成的 48 位地址或长指针称为一个逻辑地址,逻辑地址就是虚拟地址。

X86架构中有六个特殊的寄存器用于存放段基址,它们分别是CS、DS、ES、SS、FS和GS。其中 CS 用于寻址代码段,SS 用于寻址堆栈段,其他寄存器用于寻址数据段。在任何指定时刻由 CS 寻址的段称为当前代码段。当前代码段内下一条需要执行的指令的偏移地址已经存在于EIP寄存器中。此时的段基址:偏移地址就可以表示为 CS:EIP 了。

由段寄存器 SS 寻址的段称为当前堆栈段,栈顶由 ESP 寄存器给出,在任何时刻 SS:ESP 都指向栈顶,并且没有例外情况,其他四个是通用数据段寄存器,当指令中默认没有数据段时,由 DS 给出。

地址转换

通常,一个完整的内存管理系统由两个组成部分组成:访问保护和地址转换。访问保护是为了防止一个应用程序访问的内存地址是另一块程序所使用的;地址转换就是给不同的应用程序提供一个动态的地址分配方式。访问保护和地址转换是相辅相成的。

地址转换通常以内存块作为基本单位,这里解释下什么是块,大家知道在 Linux 中,一切都是文件,而文件就是由一个个的块构成的,块(block)是用于描述文件系统的组成单位,也是数据处理的基本单位。常见的块有不同大小,如 512B、1KB、4KB 等,虽然块是基本单位,但它实质上是由一个个扇区构成的。

地址转换有两种实现方式:分段机制和分页机制。x86 在内存管理的实现方式结合了分段和分页机制,下面是虚拟地址经过分段和分页后转换为物理地址的映射图

Linux 保护模式下的内存管理

针对这张图,有必要解释一下:

首先,这张图包含三个地址和这三个地址的转换过程,从大体上来看,逻辑地址会经过分段基址转换后变为线性地址,线性地址是保护模式下的段基址 + 段内偏移,因此这张图是保护模式下的地址转换图。线性地址会经过分页机制后转换为物理地址,前提是需要开启分页机制;如果没有开启分页机制,线性地址 = 物理地址。

需要再说一下逻辑地址,逻辑地址里面包含段选择子和段内偏移,段选择子这个概念我刚开始接触也比较模糊,简单一点来说可以把它理解为是保护模式下的段基址,大家知道段基址是 16 位的,而段内偏移是 32 位的。

很多书或者文章中都提到了段选择符,其实段选择子就是段选择符,这完全是翻译问题,英文都是 selector。

后面会提到段描述符,段描述符和段选择子不是一回事,但段选择子是一个 16 位的段描述符。

再和大家说一下这个图上没有写出来的内容,现在大家知道逻辑地址可以转换为线性地址,线性地址可以转换为物理地址,那么根源是如何转换的呢?实际上这里使用的方式是 MMU(内存管理单元)进行转换;而线性地址转换为物理地址使用的是分页单元的硬件电路。本文的重点不在于讨论具体的转换过程,而是将重点放在分段和分页这两个机制上。

下面来详细聊一聊分段和分页这两个机制。

分段机制

这里推荐大家先看一下我写的 "内存为什么要分段" 的那段描述。

https://www.php.cn/link/d005ce7aeef46bd18515f783fb8e87fa

多个程序在同一个内存空间中运行,不会相互干扰,这是因为分段提供了隔离代码、数据和堆栈区域的机制。如果 CPU 中有多个程序或者任务正在运行,那么每个程序都可以分配各自的一套段(包含程序代码、数据和堆栈),CPU 通过加强段之间的界限来达到防止应用程序相互干扰的目的。

一个系统中所有使用的段都包含在 CPU 的线性地址空间中。为了定位指定段中的字节,程序必须提供逻辑地址才能进行转换。逻辑地址包含段选择子和段内偏移,每个段都有一个段描述符,段描述符用于指出段的大小、访问权限和段的特权级、段类型以及段第一个字节在线性地址空间中的位置(段基址)。逻辑地址的偏移量部分加到段基址上就可以定位段中某个字节的位置,因此段基址 + 偏移量形成了 CPU 线性地址空间中的地址。

线性地址空间与物理地址空间具有相同的结构,但是它们所能容纳的段相差甚远,虚拟地址也就是逻辑地址空间可包含最多 16 K 的段,而每个段可容纳的大小为 4 GB ,所以虚拟地址总共能查找到 64TB(2 ^ 46) 的段,线性地址和物理地址的空间是 4GB (2 ^ 32)。所以,如果禁用了分页机制,那么线性地址空间就是物理地址空间。

Linux 保护模式下的内存管理

这幅图就是逻辑地址 -> 线性地址 -> 物理地址的映射图,GDT 表和 LDT 表各占一半的地址空间,各为 8192 个段,每个段最长为 4 G,从 GDT 表还是 LDT 表查询,具体从哪个表查还是要看段选择子的 TI 属性,段选择子的结构如下所示

Linux 保护模式下的内存管理

段选择子总共分为三个部分:

  • RPL(Request Privilege Level):请求特权级,表示进程应该以什么权限来访问段,数值越大权限越小。
  • TI(Table Indicator):表示应该查询哪个表,TI = 0 查 GDT 表;TI = 1 查 LDT 表。
  • Index:CPU 会自动将 Index * 8,在加上 GDT 和 LDT 中的段基址,就是要加载的段描述符。

这里没有太细致的详解一下段描述符,因为此篇还是偏向于内存管理,没有太执着于某个细节。

在GDTR中,段选择子和偏移量组成的逻辑地址可以合成段描述符,并直接保存。段选择子和段内偏移经过 MMU 后可以转换成为线性地址。

分页机制

上面我们说到,线性地址是由逻辑地址转换过来的,如果禁用了分页机制,线性地址就是物理地址,如果开启分页机制,线性地址和逻辑地址空间的数量还是不同的。一般程序都是多任务的,而多任务通常定义的线性地址空间要比物理内存容量大得多,为什么呢?地址转换映射图上画着明明线性地址和物理地址都是 4G 的大小啊。那是因为,线性地址被虚拟存储技术所虚拟化了。

虚拟存储是一种内存管理技术,使用这项技术可以让我们产生内存空间要比实际的物理内存容量大的多的错觉,其本质是把内存虚拟化了,就是说内存可能只有 4G,但是你以为内存有 64 G,所以我为什么能开那么多应用程序的原因。

分页机制其实就是虚拟化的一种实现,在虚拟化的环境中,大量的线性地址空间会映射到一小块物理内存(RAM 或者 ROM)中。当进行分页时,每个段被分割为页面(通常是4K),这些页面会被存储在物理内存或磁盘上。操作系统通过使用一个页目录和页表来维护这些页面。当程序试图访问线性地址空间中的某一个地址位置时,CPU 就会使用页目录和页表把这个线性地址转换成物理地址,再存储在物理内存上。

如果当前访问的页面不在物理内存中,CPU 就会执行中断,一般错误就是页面异常,然后操作系统会把这个页面从硬盘上读入物理内存中,然后继续从中断处执行程序。操作系统常常频繁进行页面换入和换出,这也成为一个性能瓶颈。

在分段中,每个段的长度是不固定的,最大长度为4G;而在分页中,每个页面的大小是固定的。不论在物理内存还是磁盘上,使用固定大小的页面更适合管理物理内存;而分段机制使用大小可变的块更适合处理复杂系统的逻辑分区。

尽管分段和分页是两种不同的地址转换机制,但它们在整个地址变换过程中被独立处理,每个过程都是独立的。这两种机制都使用了一种中间表来存储表项映射,但是这个中间表的结构是不同的。段表存在线性地址空间中,页表则存储在物理地址空间。

保护机制

80x86拥有两种保护机制,其中一种是通过为每个任务分配不同的虚拟地址空间来实现任务之间的完全隔离。这是通过给每个任务逻辑地址到物理地址的不同变换得到的,每个应用程序只能访问自己虚拟空间内的数据和指令,只能通过它自己的映射得到物理地址;第二种机制是保护任务,保护操作系统的内存段和一些特殊寄存器不会被应用程序所访问。下面我们就来具体探讨一下这两个任务。

任务之间的保护

每个任务会单独的放在自己的虚拟地址空间中,再经过硬件映射成为物理地址,不同的虚拟地址会变换成为不同的物理地址,不会存在 A 的虚拟地址会映射到 B 所在的物理地址的范围内,这样就会把所有的任务都隔绝开,且不同任务之间不会相互干扰。

每个任务都有各自的映射表、段表和页表,当 CPU 切换不同的应用程序或任务时,这些表也会进行切换。

虚拟地址是操作系统的抽象,也就是说虚拟地址完全是操作系统所抽象出来能够更好管理应用程序和任务的一个载体,每个任务都可以把逻辑地址映射成为虚拟地址,这也表明每个任务都可以访问操作系统,操作系统可以被所有的任务所共享。这个所有任务都具有相同虚拟地址空间的部分被称为全局地址空间(Global address space),Linux 就使用到了全局地址空间。

全局地址空间中每个任务都有自己的唯一的虚拟地址空间,这个虚拟地址空间叫做局部地址空间(Local address space)。

内存段和寄存器的特殊保护

如果将操作系统在不同任务之间的保护比喻为横向保护,那么对内存段和寄存器的保护可看作是纵向保护。为了限制对任务中各段的访问,操作系统设定了4个特权级别,以保护每个任务。

优先级分为 4 个等级,0 最高,3 最低。一般最敏感的数据会被赋予最高优先级,它们只能被任务中最受信任的部分访问,不太敏感的数据会赋予低优先级;内核操作系统访问一般是 0 级,应用程序数据一般是 3 级。每个内存段都与一个特权级相关联。

我们知道 CPU 通过 CS 从段中取得指令和数据执行,从段中取得的指令和数据是具有特权级的,一般用当前特权级(Current Privilege Level)来访问,CPL 就是当前活动代码的特权级。当应用程序尝试访问段时,将与该特权级进行比较,只有低于该段的特权级才能访问。

以上是Linux 保护模式下的内存管理的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
4 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

centos和ubuntu的区别 centos和ubuntu的区别 Apr 14, 2025 pm 09:09 PM

CentOS 和 Ubuntu 的关键差异在于:起源(CentOS 源自 Red Hat,面向企业;Ubuntu 源自 Debian,面向个人)、包管理(CentOS 使用 yum,注重稳定;Ubuntu 使用 apt,更新频率高)、支持周期(CentOS 提供 10 年支持,Ubuntu 提供 5 年 LTS 支持)、社区支持(CentOS 侧重稳定,Ubuntu 提供广泛教程和文档)、用途(CentOS 偏向服务器,Ubuntu 适用于服务器和桌面),其他差异包括安装精简度(CentOS 精

Centos停止维护2024 Centos停止维护2024 Apr 14, 2025 pm 08:39 PM

CentOS将于2024年停止维护,原因是其上游发行版RHEL 8已停止维护。该停更将影响CentOS 8系统,使其无法继续接收更新。用户应规划迁移,建议选项包括CentOS Stream、AlmaLinux和Rocky Linux,以保持系统安全和稳定。

docker原理详解 docker原理详解 Apr 14, 2025 pm 11:57 PM

Docker利用Linux内核特性,提供高效、隔离的应用运行环境。其工作原理如下:1. 镜像作为只读模板,包含运行应用所需的一切;2. 联合文件系统(UnionFS)层叠多个文件系统,只存储差异部分,节省空间并加快速度;3. 守护进程管理镜像和容器,客户端用于交互;4. Namespaces和cgroups实现容器隔离和资源限制;5. 多种网络模式支持容器互联。理解这些核心概念,才能更好地利用Docker。

docker desktop怎么用 docker desktop怎么用 Apr 15, 2025 am 11:45 AM

如何使用 Docker Desktop?Docker Desktop 是一款工具,用于在本地机器上运行 Docker 容器。其使用步骤包括:1. 安装 Docker Desktop;2. 启动 Docker Desktop;3. 创建 Docker 镜像(使用 Dockerfile);4. 构建 Docker 镜像(使用 docker build);5. 运行 Docker 容器(使用 docker run)。

centos如何安装 centos如何安装 Apr 14, 2025 pm 09:03 PM

CentOS 安装步骤:下载 ISO 映像并刻录可引导媒体;启动并选择安装源;选择语言和键盘布局;配置网络;分区硬盘;设置系统时钟;创建 root 用户;选择软件包;开始安装;安装完成后重启并从硬盘启动。

CentOS上GitLab的备份方法有哪些 CentOS上GitLab的备份方法有哪些 Apr 14, 2025 pm 05:33 PM

CentOS系统下GitLab的备份与恢复策略为了保障数据安全和可恢复性,CentOS上的GitLab提供了多种备份方法。本文将详细介绍几种常见的备份方法、配置参数以及恢复流程,帮助您建立完善的GitLab备份与恢复策略。一、手动备份利用gitlab-rakegitlab:backup:create命令即可执行手动备份。此命令会备份GitLab仓库、数据库、用户、用户组、密钥和权限等关键信息。默认备份文件存储于/var/opt/gitlab/backups目录,您可通过修改/etc/gitlab

centos怎么挂载硬盘 centos怎么挂载硬盘 Apr 14, 2025 pm 08:15 PM

CentOS硬盘挂载分为以下步骤:确定硬盘设备名(/dev/sdX);创建挂载点(建议使用/mnt/newdisk);执行mount命令(mount /dev/sdX1 /mnt/newdisk);编辑/etc/fstab文件添加永久挂载配置;卸载设备使用umount命令,确保没有进程使用设备。

centos停止维护后怎么办 centos停止维护后怎么办 Apr 14, 2025 pm 08:48 PM

CentOS 停止维护后,用户可以采取以下措施应对:选择兼容发行版:如 AlmaLinux、Rocky Linux、CentOS Stream。迁移到商业发行版:如 Red Hat Enterprise Linux、Oracle Linux。升级到 CentOS 9 Stream:滚动发行版,提供最新技术。选择其他 Linux 发行版:如 Ubuntu、Debian。评估容器、虚拟机或云平台等其他选项。

See all articles