<Linux>(极简关键、省时省力)《Linux操作系统原理分析之linux存储管理(1)》(17)

本文主要是介绍<Linux>(极简关键、省时省力)《Linux操作系统原理分析之linux存储管理(1)》(17),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Linux操作系统原理分析之linux存储管理(1)》(17)

  • 6 Linux 存储管理
    • 6.1 80x86 的分段机制
      • 6.1.1 80x86 的虚拟存储空间
      • 6.1.2 段描述符表
      • 6.1.3 逻辑地址向线形地址的转换

6 Linux 存储管理

6.1 80x86 的分段机制

Linux 最早在 intel80386 机器上开发,当前也主要运行在 intel 80386、80486 和 pentium 系列机器上。按照管理把该机器系列统称 80x86,也称 i386。

80x86 机器中用于控制和管理内存的硬件机制称为存储器管理单元 MMU(memory manage unit)。

在 MMU 控制下,80x86 具有两种存储管理模式

👉实地址模式:cpu 只能寻址 1MB 空间,MS-DOS 操作系统就工作在实地址模式下;
👉受保护的虚地址模式(保护模式):80x86 提供了虚拟存储的硬件机制,它是 OS
实现多任务存储管理以及提供存储保护的硬件基础。Linux 就是在该模式下实现其各种功能的。

6.1.1 80x86 的虚拟存储空间

1.物理地址和虚拟地址

物理地址:通常出现在地址总线上的地址称为物理地址。内存空间有物理地址确定,所以内存又称为物理地址空间。内存的最大容量由物理地址长度决定。80x86 机器的地址总线为 32 位,故有它确定的物理地址空间的范围可达 232B,即 4GB。

虚拟地址:用户作业的地址空间是由逻辑地址确定的,逻辑地址就是机器指令中使用的地址,故逻辑地址空间的最大容量由机器地址长度决定。80x86 指令地址字长度 48 位,其中 46 位用于寻址,因此80x86 的逻辑地址地址空间最大可达 64T。故 80x86 提供给程序人员使用的逻辑地址空间远远大于实际的物理地址空间,是一个虚拟的存储空间。所以逻辑地址就是虚拟地址。

为了支持多道进行并发执行以及实现存储保护,80x86 存储管理机制把 64T 的逻辑地址空间分成性质
不同的两部分:

👉全局地址空间:所有进程共享的空间,通常存放 os 的程序和数据。
👉局部地址空间:由系统分配给各个进程使用,用于存放进程各自的程序和数据。

2. 地址转换方式
80x86 在保护模式下提供了两种地址转换方式:

👉分段机制
👉分段+分页的两级地址转换方式。(本书只介绍这种转换方式)。

  1. 分段分页地址转换
    在系统运行时,逻辑地址必须转换成物理地址才能访问物理内存。80x86 中分段分页的地址转换机制中需要两级地址转换:

👉第一级:由分段机制完成逻辑地址向线性地址的转换 由分段机制完成逻辑地址向线性地址的转换。分段机制把逻辑地址空间分成若干个相互独立的地址空间,它称为线性地址空间。线性地址空间的地址称为线性地址。每个线性地址空间从 0 开始编址,80x86 中线性地址是 32 位的,因此每个线性地址空间最大 4G。在多道系统中,每个线性地址可以供一个用户进程使用,这就保证了每个进程都有自己独立的虚拟存储空间 这就保证了每个进程都有自己独立的虚拟存储空间。

地址类型说明
逻辑地址面向用户,是用户在程序设计时使用的地址空间,也就是用户程序中指令访问的地址空间;
线性地址面向进程,使进程使用的地址空间,对用户透明

👉第二级:由分页机制完成线性地址向物理地址的转换

说明:
1)在 80x86 中,虚拟地址空间的全局和局部地址空间都被划分成不同段。64T 的虚拟地址空间最多可以分 16K 个段。每个段的最大长度可达 4G;
在这里插入图片描述

2)全局地址空间和局部地址空间各自最多可以有 8K 段,分别称为全局段和局部段。
3)由于虚拟存储空间不是实际存在的,所以其中的段的数量,段的大小是不确定的,是根据需要随时建立的。当然不能超过上面提到的最大限制。

6.1.2 段描述符表

80x86 的段描述符表就是前面原理部分提到的段表。段描述符就是段表表项,每个段描述符的长度为8B。80x86 提供两种不同的段描述符:

👉全局描述符表 GDT(Global Descriptor Table):描述全局段,故系统中只有一个全局描述符表
👉局部描述符表 LDT(Local Descriptor Table):描述各个进程的各个局部段。故系统中有多少进程就有多少 LDT。

1.全局描述符表 GDT
1)80x86 中,全局描述符表 GDT 中一般包括 3 种不同种类的描述符:

👉系统内核代码段和数据段的描述符
👉进程状态段 TSS(Task State Segment)的描述符。系统中每个进程都有一个 TSS 段,用于保存该进程的上下文。所有进程的 TSS 段描述符都集中的保存在 GDT 中。
👉LDT 描述符:对各个进程的局部描述符表 LDT 进行描述的描述符,记录各个进程的局部描述符 LDT 在线性地址空间的位置和长度。每个进程 LDT 描述符在 GDT 中的位置,由系统记录在该进程 TSS 段的一个 16 位的位域中,该位域的值称为 LDT 选择符。

2)全局描述符表寄存器(GDTR):记录 GDT 在线性地址空间中的位置
在这里插入图片描述

其中:

表基址:指出 GDT 的起始地址;
表限:表限的值加 1 位 GDT 的长度。

说明:16 位的表限确定了 GDT 的最大地址空间为 64K,由于每个描述符长度为 8B,因此 GDT 最多可以拥有 8K 个描述符。每个描述符对应一个段,因此系统中最多可以有 8K 个全局段。

2.局部描述符表 LDT:描述进程各个局部段的。
3.定位 LDT
因为单处理机中某个时刻只能有一个进程处于运行状态,所以在某个时刻只有当前进程的 LDT 处于活动(使用)状态。系统需要能迅速定位活动的 LDT。

80x86 通过局部描述表寄存器 LDTR 和相应的 LDT 高速缓存来实现定位 LDT。

👉局部描述表寄存器 LDTR: 是一个 16 位寄存器,它的作用是指出当前进程的 LDT 描述符在GDT 中的位置,也就是前面提到的 LDT 选择符。在进程切换时,从进程的 TSS 中取出 LDT 选择 符,并将它放入 LDTR 中; 在地址映射时,首先从 LDTR 中得到 LDT 选择符;然后 GDT 中根据 LDT 选择符找到 LDT描述符(即得到 LDT 的位置等信息),接下来才能找到 LDT(即段表)。显然这样是会严重影响程序运行速度的。故引入了 LDT 高速缓存。
👉LDT 高速缓存: 保存从 GDT 中找到的 LDT 描述符。引入 LDT 高速缓存后,第一次仍需要完成上面提到的三个步骤,但是第一次完成时,将从GDT 中找到的该进程的 LDT 描述符保存在了 LDT 高速缓存中。这样以后地址映射时,可以直接从高速缓存中得到 LDT 的位置等信息。

LDT 高速缓存:
在这里插入图片描述
说明:

16 位的表限确定了 LDT 的最大地址空间为 64K,由于每个描述符长度为 8B,因此LDT 最多可以拥有 8K 个描述符。每个描述符对应一个段,因此系统中最多可以有 8K 个局部段。

6.1.3 逻辑地址向线形地址的转换

1.基本过程(参照原理部分)
在 80x86 中逻辑地址的格式如下所示:
在这里插入图片描述
在 80x86 中,程序执行中读取每一条指令时都需要访问代码段。这时系统把逻辑地址中的选段符装入寄存器 CS 中,把段内偏址装入指令计数器 EIP 中,然后经过硬件分段机制把逻辑地址转成指向代码段的32 位线性地址。

程序中执行读写数据的指令时,系统把指令中逻辑地址的选段符装入 DS 寄存器中,把段内偏址装入某个通用寄存器中,然后经过硬件分段机制把逻辑地址转成指向数据段的 32 位线性地址。

2.段描述符寄存器(参照原理部分,快表)
选段寄存器:上述中设计到的寄存器,因为包含了选择某个段的索引值,故又称其为选段寄存器。

80x86 中有 6 个段寄存器:CS、DS、SS、ES、FS 和 GS;

段描述符寄存器:根据程序的局部性原理,为了提高地址映射速度,减少访问内存的次数。80x86 分段机制在高速缓存中,为每个选段寄存器都配置了一个对应的段描述符寄存器,用于保存当前访问的那些段的段描述符。

这篇关于<Linux>(极简关键、省时省力)《Linux操作系统原理分析之linux存储管理(1)》(17)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/446015

相关文章

慢sql提前分析预警和动态sql替换-Mybatis-SQL

《慢sql提前分析预警和动态sql替换-Mybatis-SQL》为防止慢SQL问题而开发的MyBatis组件,该组件能够在开发、测试阶段自动分析SQL语句,并在出现慢SQL问题时通过Ducc配置实现动... 目录背景解决思路开源方案调研设计方案详细设计使用方法1、引入依赖jar包2、配置组件XML3、核心配

Java NoClassDefFoundError运行时错误分析解决

《JavaNoClassDefFoundError运行时错误分析解决》在Java开发中,NoClassDefFoundError是一种常见的运行时错误,它通常表明Java虚拟机在尝试加载一个类时未能... 目录前言一、问题分析二、报错原因三、解决思路检查类路径配置检查依赖库检查类文件调试类加载器问题四、常见

windows和Linux使用命令行计算文件的MD5值

《windows和Linux使用命令行计算文件的MD5值》在Windows和Linux系统中,您可以使用命令行(终端或命令提示符)来计算文件的MD5值,文章介绍了在Windows和Linux/macO... 目录在Windows上:在linux或MACOS上:总结在Windows上:可以使用certuti

redis中使用lua脚本的原理与基本使用详解

《redis中使用lua脚本的原理与基本使用详解》在Redis中使用Lua脚本可以实现原子性操作、减少网络开销以及提高执行效率,下面小编就来和大家详细介绍一下在redis中使用lua脚本的原理... 目录Redis 执行 Lua 脚本的原理基本使用方法使用EVAL命令执行 Lua 脚本使用EVALSHA命令

Linux之systemV共享内存方式

《Linux之systemV共享内存方式》:本文主要介绍Linux之systemV共享内存方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、工作原理二、系统调用接口1、申请共享内存(一)key的获取(二)共享内存的申请2、将共享内存段连接到进程地址空间3、将

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

Java Spring 中 @PostConstruct 注解使用原理及常见场景

《JavaSpring中@PostConstruct注解使用原理及常见场景》在JavaSpring中,@PostConstruct注解是一个非常实用的功能,它允许开发者在Spring容器完全初... 目录一、@PostConstruct 注解概述二、@PostConstruct 注解的基本使用2.1 基本代

快速修复一个Panic的Linux内核的技巧

《快速修复一个Panic的Linux内核的技巧》Linux系统中运行了不当的mkinitcpio操作导致内核文件不能正常工作,重启的时候,内核启动中止于Panic状态,该怎么解决这个问题呢?下面我们就... 感谢China编程(www.chinasem.cn)网友 鸢一雨音 的投稿写这篇文章是有原因的。为了配置完

Golang HashMap实现原理解析

《GolangHashMap实现原理解析》HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持高效的插入、查找和删除操作,:本文主要介绍GolangH... 目录HashMap是一种基于哈希表实现的键值对存储结构,它通过哈希函数将键映射到数组的索引位置,支持

Linux命令之firewalld的用法

《Linux命令之firewalld的用法》:本文主要介绍Linux命令之firewalld的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux命令之firewalld1、程序包2、启动firewalld3、配置文件4、firewalld规则定义的九大