进程调用exit()会终结当前进程,可以显式调用,
也可以隐式: c语言main函数结束时编译器会自动加入exit调用

exit是系统调用,对应内核里的sys_exit() -> do_exit()

fastcall NORET_TYPE void do_exit(long code)
{
struct task_struct *tsk = current;
int group_dead; profile_task_exit(tsk); WARN_ON(atomic_read(&tsk->fs_excl)); if (unlikely(in_interrupt()))
panic("Aiee, killing interrupt handler!");
if (unlikely(!tsk->pid))
panic("Attempted to kill the idle task!"); if (unlikely(current->ptrace & PT_TRACE_EXIT)) {
current->ptrace_message = code;
ptrace_notify((PTRACE_EVENT_EXIT << 8) | SIGTRAP);
} /*
* We're taking recursive faults here in do_exit. Safest is to just
* leave this task alone and wait for reboot.
*/
if (unlikely(tsk->flags & PF_EXITING)) {
printk(KERN_ALERT
"Fixing recursive fault but reboot is needed!\n");
/*
* We can do this unlocked here. The futex code uses
* this flag just to verify whether the pi state
* cleanup has been done or not. In the worst case it
* loops once more. We pretend that the cleanup was
* done as there is no way to return. Either the
* OWNER_DIED bit is set by now or we push the blocked
* task into the wait for ever nirwana as well.
*/
tsk->flags |= PF_EXITPIDONE;
if (tsk->io_context)
exit_io_context();
set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
} tsk->flags |= PF_EXITING; //更改标志位, 表示进程正在退出
/*
* tsk->flags are checked in the futex code to protect against
* an exiting task cleaning up the robust pi futexes.
*/
smp_mb();
spin_unlock_wait(&tsk->pi_lock); if (unlikely(in_atomic()))
printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n",
current->comm, task_pid_nr(current),
preempt_count()); acct_update_integrals(tsk);
if (tsk->mm) {
update_hiwater_rss(tsk->mm);
update_hiwater_vm(tsk->mm);
}
group_dead = atomic_dec_and_test(&tsk->signal->live);
if (group_dead) {
exit_child_reaper(tsk);
hrtimer_cancel(&tsk->signal->real_timer);
exit_itimers(tsk->signal);
}
acct_collect(code, group_dead);
#ifdef CONFIG_FUTEX
if (unlikely(tsk->robust_list))
exit_robust_list(tsk);
#ifdef CONFIG_COMPAT
if (unlikely(tsk->compat_robust_list))
compat_exit_robust_list(tsk);
#endif
#endif
if (group_dead)
tty_audit_exit();
if (unlikely(tsk->audit_context))
audit_free(tsk); tsk->exit_code = code;
taskstats_exit(tsk, group_dead); exit_mm(tsk); //释放 mm_struct if (group_dead)
acct_process();
//释放各种资源
exit_sem(tsk);
__exit_files(tsk);
__exit_fs(tsk);
check_stack_usage();
exit_thread();
cgroup_exit(tsk, 1);
exit_keys(tsk); if (group_dead && tsk->signal->leader)
disassociate_ctty(1); //减少模块的引用计数
module_put(task_thread_info(tsk)->exec_domain->module);
if (tsk->binfmt)
module_put(tsk->binfmt->module); proc_exit_connector(tsk);
//1 更新进程的亲属关系, 在进程组里为子进程重新找parent,如果找不到,则设parent为init
//2 给父进程发送相应的信号
exit_notify(tsk);
#ifdef CONFIG_NUMA
mpol_free(tsk->mempolicy);
tsk->mempolicy = NULL;
#endif
#ifdef CONFIG_FUTEX
/*
* This must happen late, after the PID is not
* hashed anymore:
*/
if (unlikely(!list_empty(&tsk->pi_state_list)))
exit_pi_state_list(tsk);
if (unlikely(current->pi_state_cache))
kfree(current->pi_state_cache);
#endif
/*
* Make sure we are holding no locks:
*/
debug_check_no_locks_held(tsk);
/*
* We can do this unlocked here. The futex code uses this flag
* just to verify whether the pi state cleanup has been done
* or not. In the worst case it loops once more.
*/
tsk->flags |= PF_EXITPIDONE; //进程退出已经完成了,设置PF_EXITPIDONE if (tsk->io_context)
exit_io_context(); if (tsk->splice_pipe)
__free_pipe_info(tsk->splice_pipe); preempt_disable();
/* causes final put_task_struct in finish_task_switch(). */
tsk->state = TASK_DEAD; //设置进程的状态为TASK_DEAD schedule(); ////调度另一个进程运行
BUG();
/* Avoid "noreturn function does return". */
for (;;)
cpu_relax(); /* For when BUG is null */
}

  

总结:
    当子进程终结时,它会通知父进程,并清空自己所占据的内存,并在内核里留下自己的退出信息(exit code,如果顺利运行,为0;如果有错误或异常状况,为>0的整数)。
    在这个信息里,会解释该进程为什么退出。父进程在得知子进程终结时,有责任对该子进程使用wait系统调用。这个wait函数能从内核中取出子进程的退出信息,并清空该信息在内核中所占据的空间(内核栈, thread_info, task_struct)。 但是,如果父进程早于子进程终结,子进程就会成为一个孤儿(orphand)进程。孤儿进程会被过继给init进程,init进程也就成了该进程的父进程。init进程负责该子进程终结时调用wait函数。
    当然,一个糟糕的程序也完全可能造成子进程的退出信息滞留在内核中的状况(父进程不对子进程调用wait函数),这样的情况下,子进程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。

Linux进程管理(四、 进程终结)的更多相关文章

  1. Linux 内核进程管理之进程ID 。图解

    http://www.cnblogs.com/hazir/tag/kernel/ Linux 内核进程管理之进程ID   Linux 内核使用 task_struct 数据结构来关联所有与进程有关的数 ...

  2. Linux进程管理 (1)进程的诞生

    专题:Linux进程管理专题 目录: Linux进程管理 (1)进程的诞生 Linux进程管理 (2)CFS调度器 Linux进程管理 (3)SMP负载均衡 Linux进程管理 (4)HMP调度器 L ...

  3. 【Android手机测试】linux内存管理 -- 一个进程占多少内存?四种计算方法:VSS/RSS/PSS/USS

    在Linux里面,一个进程占用的内存有不同种说法,可以是VSS/RSS/PSS/USS四种形式,这四种形式首字母分别是Virtual/Resident/Proportional/Unique的意思. ...

  4. Linux 内核进程管理之进程ID

    Linux 内核使用 task_struct 数据结构来关联所有与进程有关的数据和结构,Linux 内核所有涉及到进程和程序的所有算法都是围绕该数据结构建立的,是内核中最重要的数据结构之一.该数据结构 ...

  5. Linux 内核进程管理之进程ID【转】

    转自:http://www.cnblogs.com/hazir/p/linux_kernel_pid.html Linux 内核使用 task_struct 数据结构来关联所有与进程有关的数据和结构, ...

  6. linux进程管理之进程创建

    所谓进程就是程序执行时的一个实例. 它是现代操作系统中一个很重要的抽象,我们从进程的生命周期:创建,执行,消亡来分析一下Linux上的进程管理实现. 一:前言 进程管理结构; 在内核中,每一个进程对应 ...

  7. Linux内存管理 一个进程究竟占用多少空间?-VSS/RSS/PSS/USS

    关键词:VSS.RSS.PSS.USS._mapcount.pte_present.mem_size_stats. 在Linux里面,一个进程占用的内存有不同种说法,可以是VSS/RSS/PSS/US ...

  8. linux c编程:进程控制(四)进程关系

    每一个进程除了有一个进程ID外,还属于一个进程组.  进程组是一个或多个进程的集合,通常情况下,他们是在同一作业中结合起来的,同一进程组的个进程接受来自同一终端的各种信号. 每一个进程组有一个唯一的进 ...

  9. linux进程管理之进程查看

    查看进程 process ====================================================================================了解如 ...

  10. Linux内存描述之内存页面page–Linux内存管理(四)

    服务器体系与共享存储器架构 日期 内核版本 架构 作者 GitHub CSDN 2016-06-14 Linux-4.7 X86 & arm gatieme LinuxDeviceDriver ...

随机推荐

  1. jeecms首页模板自定义

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/qxy369/article/details/50387465我们在点击[查看首页]时,发现出现的并不 ...

  2. 11.5 临近csp·道别

    差不多到写这个东西的时候了? 嗯,按今天的日期来算的话,还有不到十天就是csp.感觉对我这种家伙来说应该算是终结了? 放在之前的话肯定会写很多东西的,不过现在大约有点不知道写什么比较合适. 所以只是祝 ...

  3. JasperReport报表设计4

    在JRXML模板(或JRXML文件)中的JasperReport 都是标准的 XML文件,以.JRXML扩展.所有JRXML文件包含标签<jasperReport>,作为根元素.这反过来又 ...

  4. vim编辑器操作①

    Linux文本编辑器: 行编辑器:sed 全屏编辑器:nano,vi/vim 本文主要介绍说明vim编辑器的相关使用: 其有三种模式,即: 编辑模式(默认模式).插入模式(输入模式).末行模式(内置的 ...

  5. 洛谷P4022 熟悉的文章

    题意:给定一个串集合s,每次给定一个串t,询问一个最大的L,使得存在一种划分能把t划分成若干个子串, 其中好的子串总长不小于0.9|t|.好的子串定义为长度不小于L且是s中某一个串的子串. 解:发现这 ...

  6. zoj 1001 python起步

    /*赶角还是挺好的....*/ import sys for line in sys.stdin: a=line.split() print int(a[0])+int(a[1])

  7. python禁止函数修改列表的实现方法

    python禁止函数修改列表的实现方法 有时候,需要禁止函数修改列表.例如要对裂变进行修改操作,也要保留原来的未打印的设计列表,以供备案.为解决这个问题,可向函数传递列表的副本而不是原件:这样函数所做 ...

  8. css3 炫酷下拉菜单

    <!doctype html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. 洛谷P1514 [NOIP2010提高组T4]引水入城

    P1514 引水入城 题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城 ...

  10. 初探iview

    我的js功力还是TCL,太差了~ 运行iview官网例子还有它的工程文件都运行不出来.我非常感谢那些无私开源的博主,它们无私分享自己的技术,让我学到了很多东西. iview是vue的一个UI框架之一, ...