当前位置: 首页 > java >正文

操作系统-虚拟内存篇

虚拟内存

虚拟内存的设计目标是避免程序直接操作物理内存—— 若程序直接引用绝对物理地址,可能因地址冲突导致程序互相干扰,甚至引发系统崩溃。其实现核心是 “地址隔离与映射”:

虚拟内存的概念是由操作系统为每个程序分配一套虚拟地址,然后再由一个中间结构来记录虚拟地址到真实地址的映射关系

由此我们得出结论

  • 程序使用的内存地址为虚拟内存地址
  • 硬件使用的内存地址为物理内存地址

操作系统使用CPU芯片中的内存管理单元(MMU)实现虚拟地址和真实地址的映射

那么MMU是怎么实现这种映射关系的呢

是通过内存分段和内存分页来实现的

内存分段

内存分段的核心思路是:按程序的功能模块(如代码段、数据段、栈段)划分虚拟地址空间,每个模块对应一个 “段”,再通过段表实现虚拟段到物理段的映射

虚拟地址通过段表和物理地址做映射,通过段号作为索引快速找到段基地址和段界限等信息。段基地址就是当前段在物理内存中的起始位置,加上偏移量就是这个虚拟地址需要的全部真实物理地址空间。然而分段的方式会导致2个问题的出现

  1. 内存碎片
  2. 内存交换效率低

内存碎片的产生这里就不细讲了,参考JVM中的标记-清除算法大概心里就清楚了。

不过内存碎片分为外部内存碎片和内部内存碎片,对于分段来说,是按程序大小分配的段空间,一般不存在内部内存碎片,只会存在外部内存碎片,也就是段段之间的空间无法再分配导致浪费的情况。

为了解决内存碎片的问题,引入了内存交换方法

内存交换的本质如下,a和b两个段之间有100m空间碎片无法被利用,将b传入磁盘再重传内存中,重传的时候直接紧跟a后面实现,对于这个内存交换空间也成为Swap空间,是从磁盘划分出来用于磁盘和内存的空间交换。

从这里我们大概也能知道为什么交换效率低了,空间碎片不可避免且如果启动关闭程序变得频繁,内存碎片增多,交换次数上升,而交换是通过磁盘IO来操作的,一切就不言而喻了。于是出现了内存分页

内存分页

分页的本质是将虚拟内存和物理内存也按照固定大小进行连续划分,并且一一映射,减少了内存交换的数据数量。使用段的时候,每次交换都需要以段为单位,现在交换以页为单位

如果进程需要的虚拟内存无法找到对应物理内存,系统就会产生缺页异常来进入系统内核态,由内核分配物理空间并更新页表,恢复程序正常运行

内存分页机制下,分配内存的基本单位为页,因此可能会出现内部内存碎片的问题,不过也问题不大,页本身就很小,即使有大量这点碎片无足轻重。并且每个程序只能产生1个内部内存碎片,因此不可能出现碎片过多程序拖慢的问题

分页的映射实际上是和分段差不多的,不过做了优化,由于页很小,因此页数是很多的,如果做一一映射会导致大量内存用来存储页表

为了解决上诉问题,又引入了多级页表的概念,概念图如下

一级页表的痛点

以 32 位系统、4KB 页大小为例:

  • 虚拟地址空间总大小 = 4GB,每页 4KB,因此虚拟页数量 = 4GB / 4KB = 1,048,576 个(约 100 万);
  • 若采用 “一级页表”,每个页表项需 4 字节(存储物理页号等信息),则一级页表总大小 = 100 万 × 4 字节 = 4MB。

这会导致两个问题:

  1. 空间浪费:每个程序无论实际使用多少虚拟页,都需分配 4MB 页表空间
  2. 内存占用高:若系统同时运行 100 个程序,仅页表就需占用 400MB 物理内存,资源消耗过大。

多级页表的优化逻辑

多级页表的核心是 “按需创建下级页表”—— 将虚拟地址的 “页号” 拆分为多个层级,仅为已使用的虚拟页创建下级页表,未使用的层级无需分配空间。以 “二级页表” 为例:

  1. 虚拟地址拆分:将 32 位虚拟地址拆分为 “一级页号(10 位) + 二级页号(10 位) + 页内偏移量(12 位)”;
  2. 一级页表作用:仅存储 “一级页号 → 二级页表基地址” 的映射,每个一级页表项对应一个二级页表;
  3. 二级页表作用:存储 “二级页号 → 物理页号” 的映射,仅为已使用的虚拟页创建二级页表项。

(3)二级页表的空间优势

仍以 32 位系统、4KB 页大小为例:

  • 一级页表项数量 = 2^10 = 1024 个,总大小 = 1024 × 4 字节 = 4KB;
  • 每个二级页表项数量 = 2^10 = 1024 个,总大小 = 4KB;若程序仅使用 10 个虚拟页,则仅需创建 1 个二级页表(4KB),无需创建其他 1023 个二级页表;
  • 程序总页表空间 = 一级页表(4KB) + 1 个二级页表(4KB) = 8KB,远小于一级页表的 4MB,空间利用率大幅提升。

段页式内存管理

分段的优势是 “按功能模块隔离地址”,分页的优势是 “无外部碎片、交换效率高”。通过 “段页式内存管理”—— 先分段,再分页,实现完美结合

1. 段页式的核心逻辑

将虚拟地址空间先按 “段” 划分(如代码段、数据段),每个段再按 “页” 划分(固定大小的虚拟页),物理内存仅按 “页” 划分。映射过程分为三步:

  1. 段表查询:虚拟地址中的 “段号” 查询段表,获取该段的 “页表基地址”(每个段对应一个独立的页表);
  2. 页表查询:用虚拟地址中的 “页号” 查询该段对应的页表,获取 “物理页号”
  3. 计算物理地址:物理地址 = 物理页号 × 页大小 + 页内偏移量。

2. 段页式的优势与应用

  1. Windows、Linux、macOS 这些主流操作系统均采用段页式内存管理,平衡了地址隔离性、内存利用率与访问性能;
  2. 只有很少的内部内存碎片且提高了交换效率,并且有了分段的优势,程序之间的隔离性提高
http://www.xdnf.cn/news/19246.html

相关文章:

  • 机器学习中的欠拟合与过拟合
  • 2025年如何批量下载雪球帖子和文章导出pdf?
  • 每日Java并发面试系列(5):基础篇(线程池的核心原理是什么、线程池大小设置为多少更合适、线程池哪几种类型?ThreadLocal为什么会导致内存泄漏?)
  • web渗透PHP反序列化漏洞
  • 设计模式 - 静态工厂模式 + 策略模式,
  • 【一】Django框架版本介绍
  • k8s 定时任务需求模板
  • 手动安装的node到nvm吧版本管理的过程。
  • GaussDB生产扩容引起的PANIC问题处理案例
  • HarmonyOS元服务开发
  • HarmonyOS三方库的使用
  • 计算机毕业设计 java 在线学习系统 基于 Java 的在线教育平台 Java 开发的学习管理系统
  • MongoDB 源码编译与调试:深入理解存储引擎设计 内容详细
  • 【办公类-39-06】20250830通义万相水果图(万相2.1专业Q版线描风格+万相专业2.2默认简笔画效果)
  • 淘宝利用商品关键词获取商品信息指南
  • GRPO(组相对策略优化):大模型强化学习的高效进化
  • 最强分布式锁工具:Redisson
  • Ztero文献管理工具插件设置——亲测有效
  • 【YOLO11小目标改进】多尺度前馈网络(MSFN)代码
  • Java全栈工程师的实战面试:从基础到微服务
  • 当“循环经济”遇上“小程序”,旧物回收正迎来“智慧”升级
  • 【C++】AVL树(详解)
  • 使用Python和GitHub构建京东数据自动化采集项目
  • 《动手学深度学习v2》学习笔记 | 2.3 线性代数
  • SQL语言增删改查之C与R
  • ​Windows8.1-KB2934018-x64.msu 怎么安装?Windows 8.1 64位补丁安装教程​(附安装包下载)
  • DP1.4 8K验证平台
  • 双指针:从「LC11 盛最多水的容器」到「LC42 接雨水」
  • 创维E910V10C_海思MV100芯片_优盘强刷卡刷固件包
  • 中级统计师-统计实务-第二章 统计调查设计