Back to Blog

面试题【2】‘exit()’与‘_exit()’的区别

调用 exit() 时,库层会执行以下步骤:

  1. 调用用户注册的清理函数

    • 通过 atexit() 注册的函数会按照逆序(后注册先执行)依次被调用。
    • 这一步允许程序在正式退出前完成自定义的资源释放、日志写入等工作。
  2. 刷新标准 I/O 缓冲区

    • exit() 会遍历所有打开的 FILE* 流(包括 stdinstdoutstderr),如果流是 全缓冲(默认)或 行缓冲(在交互式终端上),则把缓冲区中的数据写回底层文件描述符。
    • 这一步确保在进程结束前,所有通过 printffprintf 等函数产生的输出都已经落盘或发送到终端。
  3. 关闭打开的文件描述符

    • 对每个打开的文件描述符调用 close(),触发文件系统层面的资源回收(如写入磁盘、释放锁等)。
  4. 向父进程发送退出状态

    • 通过系统调用 exit_group(在 Linux 中)将进程的退出码 status 传递给父进程,以便 wait()/waitpid() 能够获取。
  5. 销毁内核中的进程结构

    • 内核回收进程的 PCB(进程控制块)、用户态的虚拟内存空间等。

正因为 exit() 在系统调用前加入了上述“包装”,它被视为 “不是纯粹的系统调用”,而是一套完整的用户态清理流程。

2. _exit() 的工作流程

_exit()(在 POSIX 标准中也称为 _Exit)定义在 <unistd.h>,原型如下: