进程地址空间
1.虚拟地址
我们先来看这样一段代码
结果:
我们可以发现,父子进程,输出地址是一致的,但是变量内容不一样!
怎么可能同一个变量,同一块地址,同时读取,怎么可能会读取到不同的内容呢?
我们可以得出一下结论:
- 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量
- 但地址值是一样的,说明,该地址绝对不是物理地址!
- 在Linux地址下,这种地址叫做 虚拟地址
- 我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理
2.进程地址空间
2.1概念
进程地址空间是操作系统为每个进程提供的内存空间,每个进程(fork创建出的子进程也有)都有它自己独立的进程地址空间,它包含了程序的代码段,数据段,堆栈段。
进程地址空间是一个虚拟地址空间,虚拟地址空间是相对于进程而言的,它与物理地址是一一对应的关系。
如何对应?操作系统通过【页表】的地址映射的方式,讲进程的虚拟地址空间,映射到物理内存中的物理地址。
因为这种地址空间和页表(用户级)时每一个进程都私有一份
所以只要保证,每一个进程的页表,映射的是物理内存的不同区域,就能做到,进程与进程之间互不干扰。
每个程序编译好程序的时候,每个区域都会有,都会有起始(start)和结束(end)的地址,只要把这些起始和结束的地址,存储到虚拟空间正文字段,就能找到,对应的位置。类似于这种结构
程序中每一个变量和函数都有编译器给予的虚拟地址,同样也被加载到了物理内存中。
所以当我们加载程序时,就是把我们的虚拟地址填到页表的左侧,然后把每个变量加载到物理内存后给他分配的物理地址,填充到页表的右侧。这样映射关系就建立好了。
2.2父子进程
现在我们在来看父子进程
我们看一下图在结合之前学习到的写时拷贝。
当某一个创建一个子进程,除了拷贝各种资源外,子进程会拷贝(写时拷贝)一份父进程的页表,页表内容与父进程一致。
由于写时拷贝的机制,当子进程想要修改某个物理地址上的内容时,系统会重新给子进程找一片空间。该空间上的内容与父进程的一致,子进程在此空间上做修改不影响父进程,并且系统会调整子进程页表的映射的物理空间,使得子进程页表的映射不发生冲突。