目录
前言
我们在讲C语言的时候,给大家画过这样的空间布局图。但是我们并不理解,只是知道。这个空间布局图并不是语言层面上的,而是系统层面上的。
前面学习了两张表,命令行参数表和环境变量表。这里我们又出现新的问题?☞请看代码
- 在 cnt < 5 之前,父子进程输出出来的变量值和地址是一模一样的,因为子进程按照父进程为模版(子共享父的代码和数据),父子并没有对变量进行进行任何修改。是对代码是只读。
- 在cnt == 5 之后,父子进程,输出地址是一致的,但是变量内容不一样!
得出以下结论:
- 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量。
- 但地址值是一样的,说明,该地址绝对不是物理地址!
- 在Linux地址下,这种地址叫做 虚拟地址。
- 我们在用C/C++语言所看到的地址,全部都是虚拟地址!
- 物理地址,用户一概看不到,由OS统一管理。
- OS必须负责将 虚拟地址 转化成 物理地址 。
- 虚拟地址 从可执行程序加载到内存中得到,也就是从二进制的可执行程序得到。
所以之前说‘程序的地址空间’是不准确的,准确的应该说成 进程地址空间 ,那该如何理解呢?☞下面
注❗:关于进程的地址空间会讲解3~4次,信号和多线程都会再次深入理解,这里只是入门
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 100;//数据--全局变量
int main()
{
printf("father is running,pid:%d,ppid:%d\n",getpid(),getppid());//只有父进程对数据只读
pid_t id = fork();
if (id < 0)
{
perror("fork");
return 0;
}
else if (id == 0)//子进程
{
int cnt = 0;
while(1)
{
//child
printf("I am child process,pid:%d,ppid:%d,g_val:%d,&g_val:%p\n",getpid(),getppid(),g_val,&g_val);
sleep(1);
cnt++;
if(cnt == 5)//修改
{
g_val = 300;
printf("I am child process,change g_val:%d->%d\n",100,300);
}
}
}
else
{ //father
while(1)//只读
{
printf("I am parent process,pid:%d,ppid:%d,g_val:%d,&g_val:%p\n",getpid(),getppid(),g_val,&g_val);
sleep(1);
}
}
return 0;
}
基本概念
- 进程的独立性:PCB+代码+数据(只读;写入-写时拷贝)
- 虚拟地址&物理地址
- 进程的地址空间
- 页表:虚拟地址&物理地址的映射关系
- 写时拷贝