前言(前情回顾)
进程君开发了管道这门技术后,修真界的各种沟通越来越频繁,这天进程君正与自己的孩子沟通,进程君的孩子说道:
“爸爸,昨天我看他们斗法,小明一拳打到了小刚的肚子上,小刚痛的直接投降了,看得我都肚子都疼,小明下手也太狠了”。
进程君笑道:“哈哈,你是不会疼的,因为虽然都是肚子,但是在你的身上和他的身上的不是一个器官,当然你也不会痛了,就像是你也有脑子,小美也有脑子,可你会知道小美再想什么吗?哈哈哈”。
进程君说完这句话飘然而去,留下他的孩子在哪里若有所思。
翻译成计算机语言
我有两个程序A和B,在两个程序中都向内存申请了一块空间,巧合的是A和B申请到的空间的地址都是0x0008。A和B同时内存中写入了自己的数据,且都写入成功了,请问为什么在相同的地址写入数据确没有冲突呢?这就是我们今天要讨论的话题:操作系统的虚拟内存。
进程的内存模型
记得我在前面的文章身外化身fork()里面提到过,进程的官方解释是:
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配的基本单位,是操作系统结构的基础。。。
问题来了,什么是资源?
内存就是资源
linux会给每一个进程分配一块内存空间,这个空间的结构为:
图中可以看到,对于不同的进程,操作系统会在物理内存(内存条)上申请空间,并将物理空间与内核空间进行映射。我们实际编程中不需要关心实际的物理地址是多少,因为这些物理地址被操作系统,或者说MMU(内存管理单元)映射到了0x0到0xFFFFFFFF上。但我们编写程序时操作一个地址0xFFF,实际上我们操作的就是虚拟地址,而不是内存条中实际的0xFFF的真实物理地址。想要知道物理地址,我们需要将 虚拟地址 + 偏移量 才能得到实际物理地址。
必须声明一点,我们实际进行内存映射时是很难在内存条中直接申请到连续的物理地址的,我们得到的应该是一个断断续续的物理地址空间,这些空间被MMU管理,实现了物理内存到连续的虚拟内存的映射。
此外假设我有一个3.5G的内存条,但是我仍然可以申请4G的空间,虚拟内存技术可以让程序把一些不常用的部分放入硬盘中,把需要的部分映射到内存中,当需要硬盘中的部分时,可以通过页置换来实现部分内存的重新映射。
内存映射对进程的影响
操作系统的内存管理是很深刻的一门学问,研究的过于深入不利于我们的主线学习,目前大家只需要了解基本概念即可。
这里我们来看一下内存映射对进程的影响。当我开始一个进程,操作系统会为他分配资源,进行虚拟地址映射,这样我们就可以实现进程间的内存隔离。及时在内存中同时操作地址编号相同的虚拟地址空间也不会发生数据冲突。
但是这也带来了一个弊端,就是进程间难以通过普通手段进行通信。因为两个进程的内存空间在物理上隔离。
之前介绍的匿名管道与命名管道可以完成进程间的通信,但是这些手段依赖于文件操作,需要系统调用,开销较大,如何才能实现一个低成本的沟通呢?有没有办法将两个进程的虚拟地址映射到同一片物理地址上呢?
这个问题我们下一节再说。
小结
这篇文章里我们简单介绍了操作系统的内存管理机制
主要涉及
(1)进程的内存模型
(2)虚拟地址与物理地址的映射
再次提醒
操作系统内存管理是很深刻的一门学问,研究的过于深入不利于我们的主线学习,目前大家只需要了解基本概念即可。如果特别感兴趣可以去查阅相关资料。
下一节:linux多线(进)程编程——(6)共享内存
结束语
祝各位道友早日神功大成
(线程君的儿子好像最近有了一个机缘,已经去闭关修炼了。他会给我们带来什么惊喜呢?让我们拭目以待吧!)