UNIX 进程是在某个进程调用 fork 时创建的,fork 将正在运行的可执行进程一分为二。子进程将分配到内核栈,栈尾有一个thread_struct结构体,这个结构体有一个指针指向该进程描述符task_struct。另外还会分到独立的4G的地址空间。当然这个是虚拟地址空间,由mm_struct结构体表示,mm_struct结构体里还会有成员指示实际分配到的物理地址的情况。根据缺页机制,将在需要的时候才会为虚拟地址空间分配适当大小的物理地址空间。还有其他,如文件描述符、一些变量等等。然后该进程可以执行 exec 系列中的某个系统调用,从而将当前运行的映像替换为新的映像。
当父进程先于子进程终止时,其所有子进程将由 PID 为 1 的 init 接纳。init是一个永远调用wait函数的进程。这样就不会产生僵死进程了。这个是在设计系统init时就是这样设计的。
如果子进程在父进程之前终止,则会向父进程发送一个信号,然后子进程转变为僵死状态,直到该信号得到确认,或父进程被终止。这种情况详细分析如下:
每个进程都有一个父进程,当进程退出时,其退出状态可以被父进程得到。进程退出后,它的很多资源都将被释放。比如如果没有其他进程共享,它会释放mm_struct,还有内核栈和thread_struct。只剩下task_struct还被留在内核并占用pid号。父进程调用wait函数取得子进程的退出状态信息,通过读取进程描述符得到退出状态信息,并将子进程的ID和该进程描述符从系统的进程表中删除。这些退出状态信息保存在内核中,占用很小的一块内存空间。如果不调用wait函数,则父进程得不到子进程的退出信息,子进程的ID会一直保存在系统的进程列表中。所以,此时对于系统而言,子进程还是一个却是存在的进程,占据着一个ID。由于linux系统下是有严格的