news 2026/7/1 20:58:18

通过上一篇文章的扯淡,我们应该已经明白了存储器的层次结构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
通过上一篇文章的扯淡,我们应该已经明白了存储器的层次结构
  • 不管什么程序,最后的直接/间接的编译结果都是0和1,(我们直接理解为汇编)。(这点不知道的,欢迎阅读我的另一篇文章关于跨平台的一些认识),比如这句汇编代码:mov eax,0x123456;它的意思是将内存0x123456处的内容送往eax这个寄存器。各个应用的数据共同存在内存中的。假设有一个音乐播放器应用的汇编代码中,引用了0x123456这个内存地址。但是同时运行的应用有很多,那其他应用也完全有可能引用0x123456这个地址。那为什么竟然没起冲突和错误呢?
  • 进程是计算机领域最重要的概念之一,什么是进程?进程是关于某次数据集合的一次运行活动, 是运行在它自己地址空间的一段自包容程序, 解释的通俗的点, 一个程序在运行时,我们会得到一个假象,该进程好像是独占地使用CPU和内存,CPU是没有间断地一条接一条的执行该程序的指令,所有的内存空间都是供该进程的代码和数据分配使用的。(这点不严谨,其实内存还有一部分要分给内核kernel)。说起来,这个程序就好像得到了全世界一样。,CPU是我的,内存也全部我的,妹子们还是我的。当然这是假象而已。但是这些假象又是怎么做到的呢?
  • 程序中都会引用库API,比如每个C程序都要引用stdio.h库的printf(),在程序运行时,库代码也要被加入到内存,这么多程序都引用了这个库,难道我内存中需要加很多份吗?这自然不可能,那么库代码又是怎么被所有进程共享的呢?

这些让我们细思恐极的疑问,都将通过这篇文章来给大家解答。

物理和虚拟寻址

在访问者看来,主存就是一个有M个字节大小的单元组成的数组,每字节都有一个唯一的物理地址(Physical Address, PA)。 它的访问地址和数组一样,第一个地址为0,后面地址依次为1,2,3-----M-2, M-1;这叫做线性地址空间。这种自然的访问内存的方式我们称之为物理寻址(physical addressing)

注意:在访问内存时,对于任意一个地址,(不管是第0个还是第M-1个),访问该地址的时间总是相同的

在各种数据结构中,我们都说hash表是最快的,比红黑树之类的都要快,那hash表为什么最快?那是因为hash表内部本质上是使用了数组。所以还是数组最快,那数组为什么最快?这是因为我们知道数组的起始地址以及某个元素的序号,就可以得到该元素在内存中的地址,而对于内存,访问任意一个地址,访问时间总是相同的。而类似链表,树等结构,却只能靠遍历了。(不过好的hash算法还是很难设计的,这是另外一个话题了)。

图10:一个使用物理寻址的系统

上图是一个物理寻址的示例,这是一条加载指令,它读取从物理地址4开始的4个字节,CPU通过内存总线,将指令和地址传递给主存,主存读取从物理地址4处开始的4个字节,返回给CPU。

因为这篇文章主要讨论 虚拟内存,是关于L4级主存和磁盘之间的交互问题,为行文方便,文章中有时候直接说内存代指主存。所以这些不要误以为是指L1,L2之类的缓存。如果看不懂这段话啥意思,务必看看我的上一篇文章什么是内存(一):存储器层次结构,然后再来看这篇文章。

早期计算机使用物理寻址方式,但是到了现在的多任务计算机时代,普遍使用的是虚拟寻址(virtual addressing)。如下图所示:

图11:一个使用虚拟寻址的系统

CPU 通过一个虚拟地址(virtual address,VA)来访问主存,这个虚拟地址在被送到主存之前会先转换成一个物理地址。将虚拟地址转换成物理地址的任务叫做地址翻译(address translation)

地址翻译需要 CPU 硬件和操作系统之间的配合。 CPU 芯片上叫做内存管理单元(Menory Management Unit, MMU)的专用硬件,利用存放在主存中的查询表来动态翻译虚拟地址,该表的内容由操作系统管理。

有少数现代计算机系统依旧在使用物理寻址方式,比如DSP,嵌入式系统,超级计算机系统。这些系统的主要任务是执行单一任务,不像通用性计算机那样需要执行多任务。可以想象到,物理寻址方式更快。这个道理和关于跨平台的一些认识文章中,理论上java比C++慢的道理是一样的。

前面解释完虚拟地址,那么关于文章开头时提的那些疑问,可能有些人心里面都有数了。因为那些地址都是虚拟地址,并非真实的物理内存当中的地址。基本思想已经懂了,那么剩下的我们就更具体的讨论细节。

进程地址空间


图12:进程地址空间

上图是一个64位的进程地址空间,编译器在编译程序时,将结果编译成32/64位的地址空间。虚拟寻址方式简化了编译器,链接器的工作。同样也因为虚拟内存,每个进程才能有很大的,一致的,私有的的地址空间。这方便了内存管理,保护了每个进程的地址空间不被其他进程破坏。同时也方便了共享库。

虚拟内存也是一种缓存思想

虚拟内存将主存看成是一个磁盘的高速缓存,主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据。

从概念上来说,虚拟内存被组织成为一个由存放在磁盘上的 N 个连续的字节大小的单元组成的数组,也就是字节数组。每个字节都有一个唯一的虚拟地址作为数组的索引。虚拟内存的地址和磁盘的地址之间建立影射关系。磁盘上活动的数组内容被缓存在主存中。在存储器层次结构中,磁盘(较低层L5,参见我们上篇文章图4)的数据被分割成块(block),这些块作为和主存(较高层,L4)之间的传输单元。主存作为虚拟内存(或者说磁盘)的缓存。

虚拟内存(VM)系统将虚拟内存分割成称为大小固定的虚拟页(Virtual Page,VP),每个虚拟页的大小为固定字节。同样的,物理内存被分割为物理页(Physical Page,PP),大小也为固定字节(物理页也称作页帧,page frame)。

在任意时刻,虚拟页面都分为三个不相交的部分:

  • 未分配的(Unallocated):VM 系统还未分配(或者创建)的页,未分配的页没有任何数据和它们关联,因此不占用任何内存/磁盘空间。
  • 缓存的(Cached):当前已缓存在物理内存中的已分配页。
  • 未缓存的(UnCached):该页已经映射到磁盘上了,但是还没缓存在物理内存中。

其中未分配的VP不占用任何的实际物理空间,这点要理解。32位程序地址空间就有4G,至于64G的程序它的地址空间是一个非常大的天文数字(貌似是16777216T),而目前我们的电脑高配的也就2T磁盘,16G内存。如果64位程序每个VP都映射着实际的PP。无论如何也对应不上的。并且也完全没必要一一映射,"图12:进程地址空间"中可以看到,地址空间内有大量的空白。毕竟程序不可能实际使用那么大的地址空间。

图13:VM使用主存来作为缓存

上图展示了在一个有 8 个页面的虚拟内存中,虚拟页 0 和 3 还没有被分配,所以在磁盘上不存在。虚拟页 1,4,6 被缓存在物理内存中。虚拟页 2,5,7 已经被映射分配了,但是还没有缓存在主存中。

当然,那个图上标注的不对,VP 部分,n-pN-1应该分别标注为37,不过我们找不到更合适的图了,(这种图自己画压力太大了)。所以大家知道我们假设共有8个VP就好了。

页表(page table)

系统必须得有办法判定某个虚拟页是否缓存在主存的某个地方。这具体可分为两种情况。

  • 已经在主存中,就需要判断出该虚拟页存在于哪个物理页中。
  • 不在主存中,那么系统必须判断虚拟页存放在磁盘的哪个位置,并且在物理主存中选择一个牺牲页,并将该虚拟页从磁盘复制到 主存,替换这个牺牲页。

这些功能由软硬件联合提供,包括操作系统,CPU中的内存管理单元(Memory Management Unit,MMU)和一个存放在物理内存中叫页表(page table)的数据结构,页表将虚拟页映射到物理页。每次地址翻译硬件将一个虚拟地址转换成物理地址时都会读取页表。

图14:页表

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/1 20:54:57

Playwright for .NET 版本升级实战:从1.x迁移到最新版的完整指南

1. 项目概述:为什么你的Playwright for .NET需要升级? 如果你正在用Playwright for .NET做自动化测试,并且你的项目还停留在1.x甚至更早的版本,那么这篇文章就是为你准备的。我最近刚把一个大型电商项目的测试套件从Playwright f…

作者头像 李华
网站建设 2026/7/1 20:53:12

如何用 Node.js 构建自己的网易云音乐 API 服务?

如何用 Node.js 构建自己的网易云音乐 API 服务? 【免费下载链接】NeteaseCloudMusicApiBackup https://www.npmjs.com/package/NeteaseCloudMusicApi 项目地址: https://gitcode.com/gh_mirrors/ne/NeteaseCloudMusicApiBackup NeteaseCloudMusicApiBackup …

作者头像 李华
网站建设 2026/7/1 20:50:48

JMeter性能测试面试核心能力模型与高频问题深度解析

1. 项目概述:为什么一份“高频JMeter面试题”如此重要?最近几年,软件测试领域,尤其是性能测试方向,热度持续攀升。无论是大厂还是中小公司,在追求业务稳定性和用户体验的今天,对性能测试工程师的…

作者头像 李华
网站建设 2026/7/1 20:50:20

Mac系统JMeter中文版安装与电商压测实战指南

1. 项目概述:为什么Mac用户需要关注JMeter中文版与电商压测?如果你是一名在Mac上工作的开发、测试或者运维工程师,最近又恰好被电商大促、秒杀活动或者日常的接口性能问题搞得焦头烂额,那你大概率听说过或者想试试Apache JMeter。…

作者头像 李华
网站建设 2026/7/1 20:37:24

电子系统主动散热管理与智能温控实现

1. 为什么电子系统需要主动散热管理在现代电子系统中,散热管理已经从"可有可无"变成了"生死攸关"的核心设计环节。作为一名汽车电子系统工程师,我亲眼见证过太多因散热不良导致的系统故障——从简单的性能降频到严重的硬件损毁。以车…

作者头像 李华
网站建设 2026/7/1 20:35:04

Tomcat CVE-2025-24813漏洞修复实战:从原理到生产环境升级

1. 项目概述:直面CVE-2025-24813,一次真实的Tomcat漏洞修复实战最近在梳理线上服务的安全基线时,一个编号为CVE-2025-24813的漏洞引起了我的注意。这个漏洞影响的是我们大量在用的Apache Tomcat服务器。说实话,看到“资源管理错误…

作者头像 李华