惠茹的故事远古时期的计算机(五十年前的大型机或者三十年前的个人电脑)是不用虚拟内存的,那时候要想跑一个程序,必须先把整个程序加载到物理内存里才能执行。可是内存又小又贵,而人们不仅想跑大程序,还想同时跑好几个,有限的物理内存吃不消了可怎么办呢?
于是人们想到了虚拟化。(注:其实不仅是虚拟内存,广义的虚拟化概念可以解决许许多多的计算机问题,比如大家常用的 virtual machine, virtual file system, VPN 等等都是虚拟化在各个领域的应用。)
简单来讲,虚拟内存就是让每个进程看起来都好像拥有一个大而独立的地址空间。什么意思呢?我们一个词一个词来讲。
首先说什么是地址空间(address space)。计算机的内存说白了可以想象成一块连续的数组,数组里面的每个字节都有一个唯一的地址。比方说我新买的(键盘手感巨烂的)电脑有 16GB(即bytes)的物理内存,那它的物理地址空间就是。
接下来再说大。就是说不管我实际的物理内存有多大,虚拟内存都可以假装有很大。比如我的电脑号称是 64-bit 的,也就是说我电脑上跑的每一个进程都以为它拥有一块的虚拟地址空间。
我们可以把虚拟内存看作一个缓存的工具,正在使用的部分放在物理内存里,暂时不用的部分就扔在磁盘上好了。
独立的意思是说尽管每个进程的虚拟地址空间长得都一样,但它们都是私有的。不同进程的同一个虚拟地址可以映射到不同的物理地址。
例如,所有 64-bit 程序的代码都是从内存地址 0x400000 开始的,然而不同程序其中的内容是不一样的。
这就好比说库克住了个 town house,隔壁是马斯克的 town house。尽管这两栋房子的外观设计一模一样,但库克家门口挂了个苹果:
这是怎么实现的呢?简单来讲,系统把虚拟内存和物理内存都划分为等长的 page(页),并为每个进程维护一个 page table(页表)用来将虚拟页映射到物理页。这样当我们访问一个虚拟地址时,系统就可以通过查表将其翻译为物理地址。如果这个地址所在的页当前不在物理内存中,则系统会先将它从磁盘取出来替换掉内存里另一个暂时不用的页。整个过程是由操作系统和硬件协同完成的,这里不再赘述,感兴趣的同学可以参考任何一本操作系统教材。
虚拟内存让进程的链接和加载、共享和分配内存、访问权限控制等都变得很容易。连续的虚拟页不必要在物理上连续,而不同的虚拟页也可以映射到同一个物理页。举个简单的例子,几乎所有的C 语言程序都会用到printf() 函数,于是我们在物理内存中可以只有一份 printf() 的实现,而让各个进程对应的虚拟页全都映射到同一个物理页即可。
最后我们来简要讨论一些同学们在写程序时常犯的和虚拟内存有关的错误(以下以 C 语言为例;Java 也会相应地报错或抛出异常):
1. 访问空指针或坏指针。比如指针指向的虚拟地址并没有映射到实际有意义的数据,或者我们试图去写一块只读的虚拟内存区域,都会导致 segmentation fault。
2. 访问未初始化的内存。如果一个局部变量没有初始化而我们误以为它是零,程序的结果就会不对。
3. 缓冲区溢出(buffer overflow)。例如一个函数的输入参数是一个字符串,函数里有一个固定大小的 buffer。如果我们没有检查该字符串的长度就将它拷贝到 buffer 中,一旦输入字符串超出了 buffer 的长度就会造成 buffer overflow,从而覆盖掉其它有意义的数据。
4. 缓冲区溢出有一个特例是所谓的 off-by-one error,也是同学们常犯的错误。一个长度为的数组 index 是到,此时如果访问 index 为的元素就越界了,会读到甚至覆盖掉别的数据。
构建强大编辑器:深入剖析 Prosemirror Mark 及选区与光标系统的奥秘
本文深入分析了Prosemirror 中的选区与光标系统,并分享了mark 从定义到实战的大量示例,俗话说”基础不牢,地动山摇“,没有掌握足够的工具,面对复杂场景是没有解决方案的,如有需要可以仔阅读。
通过本文你将理解rspack,并快速实现Vue2、Vue3项目配置,提升5倍多的项目构建性能,快速提高工作效率。
最近迁移前端资源到云厂商时,我遇到了一个奇怪的问题 —— 线上环境某个 CSS 资源跨域了,后果直接导致项目崩溃不可用。大领导直接找到了我的工位,激动的心,颤抖的手,问题原因就是找不到!!!
841. 钥匙和房间 思路 广度优先算法,使用一个 Set 记录访问过的房间,使用队列 queue 先进先出的特性依次遍历每一个房间,最后判断 `Set` 的大小是否等于房间数。
前言 众所周知,Vite 已然占据 web 开发的半壁江山。 无论是 Vue 项目还是 React 项目,我都习惯使用 Vite 去开发构建。 但是,有个问题一直困扰着我,那就是,项目需要兼容
24前端应届生花两月时间一点一点总结出的十万八股长文,后续还会继续更新,包括但不仅限于html/css/js/vue/webpack/nodejs/计算机网络...
本文介绍了两种基于webpack的代码修改的方法,可以通过编写webpack的babel或者plugin来修改webpack的输出结果,给出了具体的实例,对于理解webpack的原理又一些参考价值。
什么是路由 简单来说,路由就是URL到函数的映射关系。并且路由这个概念最早是出现在后端的,因为早期的网页都是服务端渲染的,比如:JSP,PHP,ASP等语言,都是直接返回渲染好的html给客户端显示。
一直听说程序员的危机在 35 岁,没想到我的危机从 25 岁就开始了。 我甚至不知道自己是不是 25 岁,也可能是 26 岁,或者 27 岁,1998 年的生日,按照 2023 - 1998 的算法就
当创建一个前端项目时,通常是使用命令行工具如create-react-app或vue-cli来快速生成项目的基础结构,但是你了解这些工具在里面执行了些什么代码吗
我们在使用 Jenkins 构建的时候,有时候需要提供一个构建好的文件包的下载地址给协作者下载使用。而不是每次都点击进去 workspace 的指定位置下载。 那么,配合 Jenkinsfile ~
十分钟教会你手写eventbus加发布npm包. 授人以鱼不如授人以渔,教会你以后自己写轮子并放到npm上给全世界人使用.
一、Dcokerfile概念 Dockerfile是一个文本文件,文件中包含了一条条指令(instrucation),用于构建镜像。每一条指定构建一层镜像,因此每一条指令的内容,就是描述该层镜像应当如
封装一个函数式组件实现前端开发中经常遇到的场景: 点击按钮弹出对话框。此组件可以作为一个模板,具备弹窗的基本功能,遵循基于构件开发的设计原则。
在 CloudWeGo 两周年之际,我们希望邀请所有的社区用户参与两周年庆典,共同见证 CloudWeGo 的又一蜕变:更多元、更易用、更极致!
|