fork 后,父子进程的在内存中是怎样的?测试环境centos7 x64
写一个测试程序:
1 |
|
输出:
1 | [parallels@centos-7 vimExercise]$ ./forkAddressTest |
一毛一样,子进程把父进程fork了一份,就像从别人的GitHub仓库fork 下来一份。再试试修改下这个子进程中的变量……
修改后的代码:
1 | if (ret == 0) { |
程序输出:
1 | [parallels@centos-7 vimExercise]$ ./forkAddressTest |
地址是一样的,但是变量内容不一样……诶?这个盒子里可以放下这两个东西吗?我觉得不行,这一个东西就把盒子占满了,另一个再放进去要么覆盖,要么就放不进去(除非可以压缩,手动滑稽)。
查阅资料:这个是映射出去的虚拟地址不是物理地址。两个不是同一个盒子,盒子里装的也是不同的东西。在C/C++ 程序中输出的地址全部都是虚拟地址,物理地址由OS统一管理。OS负责把虚拟地址转换成虚拟地址。
每次都需要物理地址和虚拟地址之间的转换,靠软件来实现转换逻辑效率是比较低的,在《计算机组成原理》和《微型计算机原理》这两门课中老师反复提到了地址之间的转换,是通过一种叫MMU的硬件设备负责地址之间的转换,硬件实现效率高。
内存管理模块负责控制进程如何访问物理内存资源。通过硬件内存管理系统(MMU)管理进程虚拟内存和机器物理内存之间的映射。每一个进程都有自己独立的虚拟内存空间,所以两个进程可能有相同的虚拟地址,但是它们实际上在不同的物理内存区域运行。MMU 提供内存保护,让两个进程的物理内存空间不互相干扰。内存管理模块还支持交换——将暂时不用的内存页换出到磁盘上的交换分区,这种技术让进程的虚拟地址空间大于物理内存的大小。虚拟地址空间的大小由机器字长决定。——Linux 概念架构的理解
在一个多任务操作系统中的每个进程都运行在它自己的内存“沙箱”中。这个沙箱是一个虚拟地址空间virtual address space,在 32 位的模式中它总共有 4GB 的内存地址块。这些虚拟地址是通过内核页表page table映射到物理地址的,并且这些虚拟地址是由操作系统内核来维护,进而被进程所消费的。每个进程都有它自己的一组页表,但是这里有点玄机。一旦虚拟地址被启用,这些虚拟地址将被应用到这台电脑上的所有软件,包括内核本身。因此,一部分虚拟地址空间必须保留给内核使用。——Anatomy of a Program in Memory
画个图我就理解了,自己也画个滑稽。
几个小时后的补充:这里再附上另外一张图,上图中稍微有一些错误,我搞清楚再总结一下。