内存管理 : 04段页结合的实际内存管理

article/2025/6/21 14:28:13

一、课程核心主题引入

这一讲,我要给大家讲的是真正的内存管理,也就是段和页结合在一起的内存管理方式。之前提到过,我们先学习了分段管理内存的工作原理,知道操作系统采用分段的方式,让用户程序能以分段的结构进行编写;后来又学习了分页管理内存,明白操作系统在管理物理内存时,通过分页机制更高效地利用内存。分段对用户和应用程序友好,分页对物理内存管理高效,所以这两种机制必须结合起来。
在这里插入图片描述

这一讲的关键,就在于探究段和页这两种机制如何结合,以及结合后实际的物理内存管理是什么样的。程序员希望用段来编写程序,物理内存希望用页来进行管理,而操作系统作为中间桥梁,既要让上层用户满意,又要高效管理下层物理内存资源,所以必须将分段和分页两种机制融合。接下来,我先给大家讲讲段页结合的思路,再深入探讨这种结合方式的具体实现。

二、段页结合的思路解析

  1. 回顾分段与分页工作原理
    • 先来回顾一下分段是怎么工作的。想象一下,有一个程序和一块内存,我们在内存中采用分区的方法,根据程序分段的数量划分出相应的区域。比如程序分成两段,就割出两个区域,然后将用户程序中的段和这些区域建立映射,把代码段放在一个区域,数据段放在另一个区域,这样应用程序就放到内存的段中了。
    • 再看看分页的工作方式。物理内存会被打散成一页一页固定大小的片,我们的程序同样也会被打散。假设程序有两个段,将这两个段也打散成若干页,然后把这些页映射到物理内存的空闲页上,分页机制的工作就完成了。
  2. 段页结合的具体方式
    • 现在要把段和页结合起来,该怎么做呢?仔细观察分段和分页的工作过程图,我们可以发现一个巧妙的方法。把程序中的段先映射到一个类似物理内存的地方,但它不是真正的物理内存,只是一个地址空间。这个地址空间可以划分成一块一块的,就像物理内存一样,不过划分出来的只是地址,还不能直接访问真实的物理内存,我们把它叫做虚拟内存

    • 具体来说,从应用程序角度出发,在虚拟内存给定的地址空间上,割出一个区域给程序中的段,这样就实现了对段的支持,段有了对应的映射。但是虚拟内存本身不能直接使用,它只是一个虚拟的地址空间,所以还需要把虚拟内存中的段再分割成固定大小的页,然后将每页映射到物理内存上。经过这两次映射,就形成了既有段又有页的内存管理模式。在这里插入图片描述

    • 从用户的角度看,程序对应到虚拟内存上,感觉就像在使用段,他们不用关心底层的复杂映射过程,只知道自己的程序段在一段地址空间上,并且可以像使用段一样连续地进行寻址访问。而从物理内存的角度,是把虚拟内存中的段映射到物理内存页上,实现了分页管理。通过引入虚拟内存这个概念,完美地将段和页结合在了一起,这就是段页式内存管理的核心轮廓。

三、段页同时存在时的重定位过程

  1. 重定位的必要性
    我们已经知道段页是如何结合工作的了,但要让程序在内存中顺利运行,还需要进行重定位,也就是地址翻译。因为用户发出的逻辑地址,像程序中使用的段号加上段的偏移地址,需要经过转换,才能找到真正的物理地址,这样程序才能在内存中正确地取指执行。

  2. 重定位的具体步骤在这里插入图片描述

    • 当用户发出逻辑地址(段号 + 段偏移)时,首先要根据段表找到一个地址,这个地址是虚拟地址。在只有分段的情况下,这个地址就是物理内存地址,但在段页结合的模式下,它还不是真正的物理地址,只是虚拟内存中的地址。
    • 得到虚拟地址后,操作系统还要根据分页机制再进行一次映射。通过虚拟地址算出页号,再结合页内偏移,组合形成物理地址。最后,操作系统把这个物理地址发送到地址总线上,程序就能访问到真正的物理内存单元,取出数据或执行指令了。整个过程需要经过两层地址翻译,第一层基于分段,第二层基于分页,这样既支持了分段,又支持了分页,用户感觉自己在使用段,而物理内存则按照页的方式进行管理和分配。

四、段页式内存下程序载入内存的过程

  1. 程序载入内存的总体步骤在这里插入图片描述
    在这里插入图片描述

    • 我们的目标是让操作系统管理内存,使用户程序能够放入内存并正常执行。在段页式内存管理下,程序载入内存的过程可以分为几个关键步骤。第一步,要在虚拟内存上割出一段区域,分配给用户程序的代码段、数据段等,然后建立段表,记录虚拟内存区域和程序段的对应关系,这一步相当于“假装”把程序段放入了内存。
    • 第二步,虽然在虚拟内存中有了映射,但程序还没有真正放到物理内存中,所以接下来要在物理内存中找到空闲页,建立页表,将虚拟内存中的区域和物理内存的页关联起来。通过磁盘读写操作,把程序真正载入到物理内存中。
    • 第三步,完成前面的操作后,程序已经在内存中了,但要能正常使用内存,还需要进行重定位,也就是前面讲的地址翻译过程,让程序中的地址能够正确对应到物理内存单元,这样程序就能顺利执行了。
  2. 结合代码分析具体操作(以fork为例)在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    • 我们从fork函数开始分析程序载入内存的过程。fork函数用于创建子进程,在这个过程中会涉及到内存的分配和映射。copy_process函数会进行一系列操作,其中copy_mem函数中的代码实现了关键步骤。

    • set_base等代码用于设置段表,这对应着第一步在虚拟内存上分配区域并建立段表的操作。通过计算,给每个进程分配一定大小的虚拟内存空间(如这里每个进程分配64兆),并将虚拟内存的起始地址赋给段表中的基址,完成对虚拟地址的分割和段表的初始化。在这里插入图片描述

    • 接下来是分配物理内存和建立页表。由于子进程是通过复制父进程创建的,所以在copy_page_tables函数中,子进程可以共用父进程已经分配好的物理内存页,只需要拷贝页表即可。通过一系列代码操作,先确定父进程和子进程的页目录,为子进程分配新的页目录项(如果需要),然后将父进程页表中的内容拷贝到子进程的页表中,并将共享的页设置为只读,同时更新内存使用计数等信息。这样,父子进程就都有了自己的虚拟内存、物理内存,并且段表和页表都已正确建立,程序成功载入内存。
      在这里插入图片描述

五、程序使用内存的过程及多进程地址分离在这里插入图片描述

  1. 程序使用内存的操作
    当操作系统把段表和页表做好后,程序就可以使用内存了。以*p = 7为例,假设p的逻辑地址经过编译后是300,首先根据逻辑地址(段号 + 段偏移)和段表中的基址算出线性地址(虚拟地址),然后内存管理单元(MMU)会根据虚拟地址和页表算出物理地址。由于这个地址转换过程如果用软件实现会比较慢,所以CPU设计了MMU这个硬件来自动完成转换功能。MMU算出物理地址(如7300)后,将其打到地址总线上,就把7存储到对应的物理内存单元中,实现了*p = 7的操作。
  2. 多进程地址分离与相互影响消除
    • 当有多个进程时,比如父子进程执行同样的代码,子进程执行*p = 8p还是300。在执行过程中,由于父子进程的段表基址不同(子进程的段表基址是根据其自身分配的虚拟内存计算的),所以算出的虚拟地址不同。
    • 又因为之前将共享的页设置为只读,当子进程要写入数据(如写入8)时,就会触发写时复制机制。此时会新申请一个内存页,修改页表,建立新的映射,将新的物理地址(如8300)与虚拟地址关联起来。这样,父进程和子进程就通过各自的映射表实现了地址的分离,避免了相互影响,每个进程都能独立地访问和使用自己的内存空间,就像我们之前讲过多进程在内存中相互影响的问题,通过段表和页表的配合,得到了完美解决。

http://www.hkcw.cn/article/kqjhrgmigr.shtml

相关文章

MCP Python技术实践

目录 1. 引言篇 1.1 什么是MCP(Model Context Protocol) 1.2 MCP的核心设计理念​ 1.3 MCP的技术背景 1.3 学习目标与内容概览 2. 基础理论篇 2.1 MCP协议架构详解 2.2 MCP消息格式与通信机制 2.3 MCP核心概念深入 3. 环境搭建篇 3.1 开发环境…

《数据结构初阶》【番外篇:二路归并的外排史诗】

【番外篇:多路归并的外排史诗】目录 前言:---------------介绍---------------一、实际情景二、外部排序什么是外部排序? 三、多路归并排序什么是多路归并排序? ---------------实现---------------四、文件归并文件二路归并排序思…

【JavaEE】多线程

5.线程启动(statrt方法) start方法内部,会调用系统api来在系统内核中创建出线程,创建完线程后会自动调用run方法。 而run方法,就只是描述这个线程要执行的任务。 start 和 run 得区别(经典面试题&#xf…

leetcode hot100刷题日记——31.二叉树的直径

二叉树直径详解 题目描述对直径的理解解答:dfs小TIPS 题目描述 对直径的理解 实际上,二叉树的任意一条路径均可以被看作由某个节点为起点,从其左儿子和右儿子向下遍历的路径拼接得到。 那我们找二叉树的直径(最大路径&#xff09…

C++ —— B/类与对象(下)

🌈个人主页:慢了半拍 🔥 创作专栏:《史上最强算法分析》 | 《无味生》 |《史上最强C语言讲解》 | 《史上最强C练习解析》|《史上最强C讲解》 🏆我的格言:一切只是时间问题。 ​ 目录 一、再谈构造函数 1…

Python贷款计算器:等额本息与等额本金还款方案详解

Python贷款计算器:等额本息与等额本金还款方案详解 一、摘要二、整体架构流程1. 输入处理层2. 核心计算层3. 结果输出层三、具体技术细节1. 等额本息实现解析2. 等额本金实现解析3. 输出格式化技术四、运行1.等额本息2.等额本金五、结论附:完整代码一、摘要 本文介绍一款基于…

【Python专栏】Python中的浮点数类型

Python中的浮点数类型是有范围的,我们如何知道浮点数的范围呢?我们可以使用如下的方法来确定我们的浮点数的上下限。 Import sys Print(sys.float_info) 在编程语言中,如果我们计算的是浮点数计算,我们都会碰到计算精度的问题。原因是因为Double

【判断数字递增】2021-12-19

缘由用C/C实现数字递增问题?-编程语言-CSDN问答 给定一个正整数 n,请判断 n 的所有数位上的值是否从左到右是严格递增的。   例如:1589 是严格递增的。   再如:1336 不是严格递增的,中间有相同的 3。   再如&am…

计算机网络之路由表更新

1.解题思路 对新接收到的路由表进行更新,全部"距离"1,且"下一跳路由器"都写成发送方路由器的名称。 开始对比新表和原来的路由表 1.看目的网络 如果是新的目的网络,则直接把对应的各项信息填入表中;如果是相同…

前端学习(7)—— HTML + CSS实现博客系统页面

目录 一,效果展示 二,实现博客列表页 2.1 实现导航栏 2.2 实现个人信息 2.3 实现博客列表 三,实现博客正文页 3.2 复用 3.4 实现博客正文 四,实现博客登录页 4.1 版心 4.2 登录框 五,实现博客编辑页 5.1 …

使用 HTML + JavaScript 实现一个日历任务管理系统

在现代快节奏的生活中,有效的时间管理变得越来越重要。本项目是一个基于 HTML 和 JavaScript 开发的日历任务管理系统,旨在为用户提供一个直观、便捷的时间管理工具。系统不仅能够清晰地展示当月日期,还支持事件的添加、编辑和删除操作&#…

最卸载器——Geek Uninstaller 使用指南

Geek Uninstaller 是一款轻量级的第三方卸载工具,专为 Windows 系统设计,提供比系统默认卸载器更彻底的应用清除能力。它体积小、绿色免安装,使用起来简单直观,但功能却不含糊。 一、为什么要用 Geek Uninstaller? Wi…

在QT中,利用charts库绘制FFT图形

第1章 添加charts库 1.1 .pro工程添加chart库 1.1.1 在.pro工程里面添加charts库 1.1.2 在需要使用的地方添加这两个库函数,顺序一点不要搞错,先添加.pro,否则编译器会找不到这两个.h文件。 第2章 Charts关键绘图函数 2.1 QChart 类 QChart 是…

5G-A:开启通信与行业变革的新时代

最近,不少细心的用户发现手机信号标识悄然发生了变化,从熟悉的 “5G” 变成了 “5G-A”。这一小小的改变,却蕴含着通信技术领域的重大升级,预示着一个全新的通信时代正在向我们走来。今天,就让我们深入了解一下 5G-A&a…

web安全开发,在线%机器学习异常流量检测系统%开发demo

框架:html,css,jquery,echart,python,flask,sklearn,uniapp,apk,kdd和nsl,mysql数据库。 经验心得 这是一个响应式的 H5 页面,适用于手机端和电脑端,平板,各种小程序。本来想vxxx小程序和AndroidStudo写两个但是工作量太多了加上也不是商用&…

每日算法-250531

每日算法学习记录 - 250531 今天完成了两道 LeetCode 题目,主要用到了前缀和的思想。记录如下: 1. 2559. 统计范围内的元音字符串数 题目 思路 前缀和 解题过程 我们可以先预处理出一个前缀和数组 nums,其中 nums[i] 表示 words 数组中从下…

CTFHub-RCE eval执行

观察源代码 我们可以发现源代码是request请求,所以我们可以通过GET或者POST请求,利用cmd参数进行命令执行 判断是Windows还是Linux 用GET请求 /?cmdsystem(ipconfig); 无回显 说明不是Windows系统 /?cmdsystem(ifconfig); 可以发现有回显&…

MCP架构深度解析:从基础原理到核心设计

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 持续学习,不断…

MySql(九)

目录 条件查询 1&#xff09;准备一张表 2&#xff09;插入数据 3&#xff09;条件查询格式 1---比较运算符 >大于 2---比较运算符 < 小于 3---比较运算符 > 大于等于 4---比较运算符 < 小于等于 5---比较运算符 ! 不等于 6---比较运算符 <> 不等于 7---比较…

赛博算命之“帝王之术”——奇门遁甲的JAVA实现

个人主页 文章专栏 文章目录 个人主页文章专栏 #前言#背景介绍#原理分析**一、干支系统计算**1. **四柱干支生成**2. **旬首与空亡判断** **二、九宫格与洛书模型**1. **地盘固定排布**2. **天盘动态移动** **三、阴阳遁与局数计算**1. **阴阳遁判断**2. **局数计算** **四、九…