而虚拟内存的引入正是要解决上述的问题 , 虚拟内存引入之后 , 进程的视角就会变得非常开阔 , 每个进程都拥有自己独立的虚拟地址空间 , 进程与进程之间的虚拟内存地址空间是相互隔离 , 互不干扰的 。每个进程都认为自己独占所有内存空间 , 自己想干什么就干什么 。

文章插图
系统上还运行了哪些进程和我没有任何关系 。这样一来我们就可以将多进程之间协同的相关复杂细节统统交给内核中的内存管理模块来处理 , 极大地解放了程序员的心智负担 。这一切都是因为虚拟内存能够提供内存地址空间的隔离 , 极大地扩展了可用空间 。

文章插图
这样进程就以为自己独占了整个内存空间资源 , 给进程产生了所有内存资源都属于它自己的幻觉 , 这其实是 CPU 和操作系统使用的一个障眼法罢了 , 任何一个虚拟内存里所存储的数据 , 本质上还是保存在真实的物理内存里的 。只不过内核帮我们做了虚拟内存到物理内存的这一层映射 , 将不同进程的虚拟地址和不同内存的物理地址映射起来 。
当 CPU 访问进程的虚拟地址时 , 经过地址翻译硬件将虚拟地址转换成不同的物理地址 , 这样不同的进程运行的时候 , 虽然操作的是同一虚拟地址 , 但其实背后写入的是不同的物理地址 , 这样就不会冲突了 。
3. 进程虚拟内存空间上小节中 , 我们介绍了为了防止多进程运行时造成的内存地址冲突 , 内核引入了虚拟内存地址 , 为每个进程提供了一个独立的虚拟内存空间 , 使得进程以为自己独占全部内存资源 。
那么这个进程独占的虚拟内存空间到底是什么样子呢?在本小节中 , 笔者就为大家揭开这层神秘的面纱~~~
在本小节内容开始之前 , 我们先想象一下 , 如果我们是内核的设计人员 , 我们该从哪些方面来规划进程的虚拟内存空间呢?
本小节我们只讨论进程用户态虚拟内存空间的布局 , 我们先把内核态的虚拟内存空间当做一个黑盒来看待 , 在后面的小节中笔者再来详细介绍内核态相关内容 。首先我们会想到的是一个进程运行起来是为了执行我们交代给进程的工作 , 执行这些工作的步骤我们通过程序代码事先编写好 , 然后编译成二进制文件存放在磁盘中 , CPU 会执行二进制文件中的机器码来驱动进程的运行 。所以在进程运行之前 , 这些存放在二进制文件中的机器码需要被加载进内存中 , 而用于存放这些机器码的虚拟内存空间叫做代码段 。

文章插图
在程序运行起来之后 , 总要操作变量吧 , 在程序代码中我们通常会定义大量的全局变量和静态变量 , 这些全局变量在程序编译之后也会存储在二进制文件中 , 在程序运行之前 , 这些全局变量也需要被加载进内存中供程序访问 。所以在虚拟内存空间中也需要一段区域来存储这些全局变量 。
- 那些在代码中被我们指定了初始值的全局变量和静态变量在虚拟内存空间中的存储区域我们叫做数据段 。
- 那些没有指定初始值的全局变量和静态变量在虚拟内存空间中的存储区域我们叫做 BSS 段 。这些未初始化的全局变量被加载进内存之后会被初始化为 0 值 。
经验总结扩展阅读
- 神话中高要一步一步往上爬是第几集?
- 神话一步一步爬到最高是几集?
- 总以为她会永远陪我一步一步慢慢走是什么歌
- 爱情不会一步到位而是会经过颇多挫折才圆满的星座
- Dubbo 03: 直连式 + 接口工程
- 一篇文章带你了解热门版本控制系统——Git
- 一篇文章带你了解网页框架——Vue简单入门
- 一直在等待爱却不敢主动迈出一步的星座
- 我用canvas带你看一场流星雨
- 一篇文章带你掌握MyBatis简化框架——MyBatisPlus
