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

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

  • 不管什么程序,最后的直接/间接的编译结果都是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:页表

http://www.gsyq.cn/news/1616707.html

相关文章:

  • Selenium自动化测试环境部署与WebDriver实战指南
  • Pytest.ini 深度解析:从基础配置到企业级测试框架定制
  • 本科毕设用的Pygame横版闯关游戏:玛丽冒险完整开发包(含exe、源码、操作文档与音画素材)
  • Frida动态Hook技术:绕过APK证书验证的实战指南
  • 如何用MeEdu的智能多云引擎重构在线教育基础设施:4个架构决策解析
  • 【Java从入门到精通】第8篇:封装的艺术——private、getter/setter与JavaBean的约定
  • 从靶场到实战:基于PIKACHU的XSS漏洞后台安全配置全解析
  • Java线程切换对缓存的影响的剖析
  • 2026年论文AI软件哪个强?主流工具横向对比
  • 在 Ubuntu 26.04 上安装 Docker CE 教程
  • 铜钟音乐:构建纯净听歌体验的终极免费音乐平台完整指南
  • JMeter SSH Sampler性能测试插件:原理、配置与实战应用
  • 让 AI Agent 学会收发邮件:Agent Mail CLI 配置体验与玩法
  • Jetson TK1时区与时间配置实战指南
  • 探索macOS Catalina Patcher:让老旧Mac焕发新生的完整技术指南
  • Token工厂崛起:AI算力底座从“资源供给”向“生产范式”跃迁的观察
  • Server 可观测性集成:OpenTelemetry 埋点、结构化日志与审计流水线
  • Pwn2Own事件后QNAP NAS紧急安全修复与深度防护指南
  • Counterfeit-V3.0:如何突破AI绘画的构图限制?
  • 10余种 智慧航拍-无人机拍摄1W例高分辨率10余种道路损害图数据集 无人机道路病害检测数据集 裂缝 龟背坑洼检测
  • DownKyi终极使用指南:快速掌握B站视频批量下载技巧
  • 遗传算法实战:N皇后问题的Python实现与调参避坑指南
  • Sigmoid与Softmax:激活函数核心区别解析
  • NGA论坛终极优化指南:免费开源脚本让你的浏览效率提升300%
  • 构建企业级智能文档平台:AnythingLLM架构深度解析与实战指南
  • 手机号码定位技术终极指南:如何快速查询电话号码归属地
  • 高准确率AI编程工具每日3000万Token,新人白嫖7天会员
  • 百度网盘直链解析完整指南:5分钟实现免费高速下载
  • 当速度为0时该球达到它路径的最高点?为什么就是最高点呢?在向上的过程中,速度是正的,在向下的过程中,速度是负的,而当球从向上变为向下运动,其速度一定是0是0为什么就是路径的最
  • 在 Ubuntu 26.04 (WSL2) 上通过阿里云镜像源安装 Docker CE 完整教程