虚拟内存及内存管理机制

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

段页式内存管理

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

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

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

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

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

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

相关推荐
捂月40 分钟前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
瓜牛_gn1 小时前
依赖注入注解
java·后端·spring
Estar.Lee1 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
喜欢猪猪1 小时前
Django:从入门到精通
后端·python·django
一个小坑货1 小时前
Cargo Rust 的包管理器
开发语言·后端·rust
bluebonnet271 小时前
【Rust练习】22.HashMap
开发语言·后端·rust
uhakadotcom2 小时前
如何实现一个基于CLI终端的AI 聊天机器人?
后端
Iced_Sheep2 小时前
干掉 if else 之策略模式
后端·设计模式
XINGTECODE3 小时前
海盗王集成网关和商城服务端功能golang版
开发语言·后端·golang
程序猿进阶3 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露