虚拟内存及内存管理机制

图源自 小林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,快表)中,加快了虚拟地址的转换。

段页式内存管理

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

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

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

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

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

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

相关推荐
程序员cxuan2 分钟前
Claude Code 为了封禁中国用户,竟然在代码里下毒
人工智能·后端·程序员
郡杰8 分钟前
Git基础与开发平台搭建
git·后端
ServBay25 分钟前
MCP (Model Context Protocol) 深度指南,协议原理、Python 实现与生产级安全实践
后端·ai编程·mcp
道友可好1 小时前
Claude Code 泄露源码里的 89 个秘密
前端·人工智能·后端
用户8356290780511 小时前
使用 Python 保护和取消保护 Excel 工作表和工作簿
后端·python
Java面试题总结2 小时前
CubeSandbox 实战:从零部署到快照/克隆/回滚全体验
后端
Csvn2 小时前
Python 开发技巧:函数式编程与 lambda 进阶
后端
考虑考虑2 小时前
nginx配置ssl
运维·后端·nginx
uhakadotcom2 小时前
Python 中,`None` 不等于 `False`导致的问题
后端·面试·github
SamDeepThinking2 小时前
面向对象真正管理的,不是对象,而是依赖
java·后端·程序员