进程的创建过程:
此处假设linux系统内存为4G空间。
进程创建前,为一个存储在硬盘的程序,此时的程序拥有4G的虚拟内存,并且有1G空间直接被系统内核所占用,余下3G虚拟内存被系统程序分配。
由高至低
系统内核此处占用1G空间 |
剩下3G空间被合理分配 最上为栈空间(由上至下分配空间) 其次是堆空间(由下至上分配空间) ------------------------------------------------------------- 接下来的空间由一些变量空间和代码段所占用 .bss .data .rodata .text(代码段) .init(启动部分) |
程序在终端运行的时候,在内存运行的终端程序bash会将自身复制一份出来,并且同样的在内存中运行。
复制完成之后,会根据将要在内存中运行的程序在虚拟内存中的数据分配,重新的将bash副本中的数据改写,变成即将运行的新的进程。
所以在linux系统运行的进程会有一个父进程,其意思即为从一个进程中复制得出的新的进程。
程序中创建子进程fork函数
在程序运行过程中使用fork函数,系统会自动的创建一个与该函数同名的子进程。
父进程 | 子进程 |
栈 堆 数据段 | 栈 堆 数据段 |
int main(void) { ... fork(); ... } fork返回子进程的ID号 | 与父进程共用 代码段 fork返回的值为0 |
=================================华丽分割线==================================
2017.1.3补充
对fork函数创建子进程,其代码段共享以及COW(Copy On Write)写时复制技术的理解加深
码了一段代码想看看fork函数出来的所有子进程其对应的Id号,以及其父进程ID号还有组ID号
具体如下
#include <stdio.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
int main(void)
{
pid_t id = fork();
pid_t id2,id1;
if(id<0)
{
printf("fork failed:%s",strerror(errno));
return -1;
}
else if(id == 0)
{
if(setpgrp()==-1)//It is set the id of itself as the new groupid
printf("set group id is failed:%s",strerror(errno));
printf("I'm a child p[%d],ppid[%d],pgid[%d]\n",getpid(),getppid(),getpgrp());
}
else
{
printf("I'm father p[%d],ppid[%d],pgid[%d]\n",getpid(),getppid(),getpgrp());
id1 = fork();
if(id1<0)
{
printf("fork failed:%s",strerror(errno));
return -2;
}
else if(id1 == 0)
{
printf("I'm the second child p[%d],ppid[%d],pgid[%d]\n",getpid(),getppid(),getpgrp());
id2 = fork();
if(id2<0)
{
printf("fork failed:%s",strerror(errno));
}
else if(id2 == 0)
{
printf("I'm the groundchild p[%d],ppid[%d],pgid[%d]\n",getpid(),getppid(),getpgrp());
}
}
}
sleep(1);
return 0;
}
这是一个主进程创建两个子进程分别为child1,child2。然后在child2中再次fork创建一个孙子进程。
每个进程都打印出各自的id号,pid号,gid号。分别对应本身id,父进程id,组进程id。
正常的结果应该是先输出父进程,然后child1进程,child2进程,groundchild进程
但是最后的运行结果却是
I'm father p[13564],ppid[11337],pgid[13564]
I'm the second child p[13566],ppid[13564],pgid[13564]
I'm a child p[13565],ppid[13564],pgid[13564]
I'm the groundchild p[13567],ppid[13566],pgid[13564]
我一开始以为是不分先后,可能是后面的执行了,多运行几次可能就会出现不同的结果。
但是不论我怎么运行结果还是这个。
如果second child先输出结果,就是说child2进程要比child1进程要快。
后来经过各种测试,发现原来是因为fork的时间与printf的时间相差不同。
突然想起cow写时复制技术,这个技术是用在fork进程的时候,子进程与父进程共用同一段代码,所有的变量都暂时不复制,当需要为该变量赋值的时候则将变量复制到子进程的栈空间中。
child1是在id定义的时候就已经fork出来,经过了变量的声明,而child2是在父进程判断之后被fork出来,其开始时间比child1晚。
child2不需要写入变量,则不需要将父进程的变量复制一份出来,减去了复制的时间。