1.问题的引入
如下的在centos的版本下,Linux程序如下:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
int g_val=10;
int main()
{
pid_t id=fork();
if(id==0)
{
g_val=20;
printf("g_val=%d address:%p\n",g_val,&g_val);
}
else
{
printf("g_val=%d address:%p\n",g_val,&g_val);
}
return 0; }
当我们使用fork函数创建子进程的时候,改变了全局变量,应该会出现两个不同的地址,结果让人很吃惊
两个不同的全局变量,出现不同的值,地址却是相同的,这是不是很奇怪,其实这是进程的虚拟地址的原因。
2.进程虚拟地址空间
通过上面的例子我们知道变量内容不一样,所以父子进程输出的变量绝对不是同一个变量,但地址值是一样的,说明,该地址绝对不是物理地址!在Linux地址下,这种地址叫做虚拟地址
我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理OS必须负责将 虚拟地址转化成物理地址。
那虚拟地址转化成物理地址是通过什么转化的呢,答案是页表。
页表中的虚拟地址可以映射对应的物理地址
所以我们通过图来看这个过程就可以理解虚拟地址了
这是父进程的pcb中有对应的虚拟地址,在虚拟地址中的对应区域中创建一个全局变量
创建子进程后,当我们需要改变父进程的数据时,会发生写时拷贝,在物理内存中开辟空间拷贝g_val全局变量。
这样我们就可以看到不同的值却出现一样的地址。
这样做的目的有三个:
1.让进程以统一的视角看待内存,保证每个对应的数据和代码在不同的区域,方便管理。
2.增加进程的虚拟空间可以让我们访问内存的时候,增加一个转换的过程,在这个转化的过程中,可以对我们的寻址请求进行审查,所以一旦异常访问,直接拦截,该请求不会到达物理内存,保护物理内存。
3.因为有地址空间和页表的存在,将进程管理模块,和内存管理模块进行解耦合。
今天是1024程序员节,祝所有的程序员可以健健康康,赚大米,我今天发表的博客正好赶上了,我很感谢我的女朋友小泽和我的家人一直陪在我的身边,我会努力成为更好的自己,陪着他们。