虚拟内存及内存管理机制

图源自 小林coding

虚拟内存是什么?

虚拟内存是一种计算机系统管理内存的技术,它使操作系统能够将物理内存(RAM)和硬盘存储结合使用。虚拟内存的主要作用包括以下几点:

  • 扩展物理内存的使用: 虚拟内存允许系统将硬盘上的部分空间(称为交换区或页面文件)作为扩展的内存来使用。当物理内存不足时,操作系统会将不常使用的内存页面(数据或程序代码的部分)从RAM中移到硬盘的交换区,这样可以释放更多的RAM给活跃的进程使用。

  • 内存隔离和保护: 每个进程运行在自己的虚拟地址空间中,互相独立。这意味着一个进程无法直接访问其他进程的内存,从而提高了系统的安全性和稳定性。

  • 提高内存管理效率: 虚拟内存通过分页(paging)或分段(segmentation)机制来实现内存的灵活管理,避免内存碎片的产生,并允许系统灵活地分配和回收内存。

简单来说,虚拟内存提高了系统的内存利用率和安全性,使得程序在运行时即便超出了物理内存的容量,系统依然能够继续运行。

内存分段机制

为什么有分段机制

程序是由若干个逻辑分段组成的,如可由代码分段、数据分段、栈段、堆段组成。不同的段是有不同的属性的,所以就有分段的形式把这些段分离出来。

虚拟地址和物理地址是如何映射的?

虚拟地址由两部分组成:段选择因子和段内偏移量。 段选择因子包括段号。

段表保存了段的基地址、段的界限等,虚拟地址中的段内偏移量应该在 0 和段界限之间,如果段内偏移量合法,那么物理内存地址就等于段基地址加上段内偏移量 。

缺点

1、外部内存碎片问题。 由于内存分段管理可以做到段根据实际需求分配内存,有多少需求就分配多大的段,所以不会出现内存内部碎片问题。但是假如两个不连续的段的内存被回收了,这两块内存无法合并成一个大的内存,所以会产生两个外部内存碎片。

2、内存交换效率低。 解决外部内存碎片的方法是内存交换。先将分隔内存碎片的程序占用的内存写道磁盘上,再从磁盘上读回内存,这样就能合并两个分开的内存碎片。但是由于磁盘的 IO 很慢,并且每次交换都需要将大段的内存写入读取,所以会使机器卡顿。

内存分页机制

为什么有内存分页机制

为了解决内存分段的外部内存碎片和内存交换效率低 的问题。要解决这些问题,那么就要想出能少出现一些内存碎片 的办法。另外,当需要进行内存交换的时候,让需要交换写入或者从磁盘装载的数据更少一点,这样就可以解决问题了。这个办法,也就是内存分页。

  • 内存分页机制,页与页之间是紧密排列的,所以不会有外部碎片(但是如果程序不足一页,会产生内部碎片)。
  • 如果内存空间不够,操作系统只会换出换入少量的页,不会花太多时间。

因此内存交换的效率就相对比较高。

虚拟地址和物理地址是如何映射的?

分页是把整个虚拟和物理内存空间切成一段段固定尺寸的大小。这样一个连续并且尺寸固定的内存空间我们叫页(Page)。在 Linux下,每一页的大小为4KB。

虚拟地址由页号和页内偏移量组成,虚拟地址与物理地址之间通过页表来映射,如下图:

对于一个内存地址转换,其实就是这样三个步骤:

  • 把虚拟内存地址,切分成页号和偏移量;
  • 根据页号,从页表里面,查询对应的物理页号,
  • 直接拿物理页号,加上前面的偏移量,就得到了物理内存地址。

缺点

页表占用空间大。

32 位环境下,虚拟地址空间有 2^32 = 4GB,假设一个页的大小是 2^12 =4KB,那么就需要 2^20 = 1MB 个页,每个页需要 4B 存储,那么 4GB 空间的映射就需要有 4MB 的内存来存储页表。每个进程都有自己的页表,假设有 100 个进程就需要 400MB 的内存来存储页表,占用了很大的内存。

解决方式

多级页表。

把 1MB 个页表项再分页,将一级页表分为 1024 个二级页表,每个二级页表存储 1024 个页。

一级页表和二级页表结合起来能够覆盖全部虚拟地址空间。(页表一定要覆盖全部虚拟地址空间。)

如果某个一级页表的页表项没有用到,那么就不需要创建这个页表项对应的二级页表,也就省去了 1KB 个页的内存。

TLB。

多级页表虽然解决了空间上的问题,但是虚拟地址到物理地址的转换就多了几道转换的工序,这就带来了时间上的开销。由于程序空间局部性的存在,把最常访问的几个页表项存储到高速缓存(TLB,快表)中,加快了虚拟地址的转换。

段页式内存管理

  • 先将程序划分为多个有逻辑意义的段,也就是前面提到的分段机制;
  • 接着再把每个段划分为多个页,也就是对分段划分出来的连续空间,再划分固定大小的页,

这样,地址结构就由段号、段内页号和页内位移 三部分组成。

用于段页式地址变换的数据结构是每一个程序一张段表,每个段又建立一张页表,段表中的地址是页表的起始地址,而页表中的地址则为某页的物理页号,如图所示:

段页式地址变换中要得到物理地址须经过三次内存访问:

  • 第一次访问段表,得到页表起始地址;
  • 第二次访问页表,得到物理页号;
  • 第三次将物理页号与页内位移组合,得到物理地址。

可用软、硬件相结合的方法实现段页式地址变换,这样虽然增加了硬件成本和系统开销,但提高了内存的利用率。

相关推荐
量化分析码农5 分钟前
【Python量化策略评估体系 #02】5 个因子,谁真贡献 Alpha?单因子归因 + MPA 多因子分解实战
后端
SimonKing7 分钟前
Qoder中Qwen3.8-Flash 限时免费使用
java·后端·程序员
爱勇宝9 分钟前
裁员裁掉了那个干了14年的人:我这才看清职场的5条潜规则
前端·后端·程序员
花间相见11 分钟前
【计算基础|网络01】网络模型与一次完整请求全景
后端·http
2501_9339232518 分钟前
SpringCloud:通过订单服务认识什么是微服务
spring boot·后端·spring cloud
小番茄程序猿20 分钟前
RAG 的 precision 只有 0.55,我以为检索烂了,MRR 一测才发现是我用错了尺子
java·后端
llqbzllll20 分钟前
MySQL 索引为什么会失效?用同一张表前后 EXPLAIN 定位原因
后端
程序猿_极客1 小时前
【免费】2026分享一套优质的基于Java的电子产品抢购管理系统的设计与实现(智能推荐算法+可视化图表),源码+文档+视频详解(讲解)
java·spring boot·后端·协同过滤·电子产品抢购系统
小羊没烦恼!1 小时前
Windows Azure Platform体验(1):Windows Azure
java·大数据·后端·python·flask·word·.net
小小张说故事1 小时前
Python 装饰器到底是个啥?从 @ 符号到手写一个,5 个例子讲透
后端·python