研究背景:
-
kernel 2.6.32
-
32位
回顾程序地址空间
上段代码感受一下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
pid_t id = fork();
if (id < 0)
{
perror("fork");
return 0;
}
else if (id == 0)
{ // child
printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
else
{ // parent
printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
sleep(1);
return 0;
}
观察输出结果:发现父子进程的打印出的地址都是相同的 0x601058 ,这是因为父子并没有堆变量进行任何的修改。 下面稍微变更一下代码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 0;
int main()
{
pid_t id = fork();
if (id < 0)
{
perror("fork");
return 0;
}
else if (id == 0)
{ // child,子进程肯定先跑完,也就是子进程先修改,完成之后,父进程再读取
g_val = 100;
printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
else
{ // parent
sleep(3);
printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
}
sleep(1);
return 0;
}
发现父子进程时在打印时是同一块地址,但是g_val的值却不一样,则可以得出结论
- 变量内容不一样,所以输出的值绝不是同一个变量
- 但地址是一样的,所以说明这里的地址绝不是物理地址
- 在Linux下我们叫这种地址为虚拟地址
- 我们C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS进行管理
OS必须负责将虚拟地址转化成物理地址!!
进程地址空间
所以之前说的程序地址空间是不准确的,如图!
上面的图就足矣说名问题,同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被映射到了不同的物理地址!