背景:程序退出發現被強制退出,而不是正常的退出。正常退出是發送15信號,而異常退出是發送信號9,強制退出。退出機制是先發送信號15,然后6s內沒有退出完成,會發送信號9。通過查看退出流程,是將初始化申請的內存,資源全部釋放掉。最后通過exit退出。通過加打印看到exit退出耗時高。去查看退出函數還有_exit退出耗時底。
原因是exit退出會先進入清理注冊回調,刷新打開的文件緩沖區,關閉打開的文件描述符,最后調用_exit退出。_exit是直接退出。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/wait.h>#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>long long get_time_us() {struct timeval tv;gettimeofday(&tv, NULL);return tv.tv_sec * 1000000LL + tv.tv_usec;
}
// 清理函數
void cleanup() {printf("Cleanup function called.\n");
}// 測試 exit() 的耗時
void test_exit() {long long start;// 注冊清理函數atexit(cleanup);printf("Testing exit()...\n");start = get_time_us();printf("This is a test for exit().\n"); // 輸出到緩沖區fflush(stdout); // 確保緩沖區刷新exit(0); // 調用 exit(),會刷新緩沖區并執行清理
}// 測試 _exit() 的耗時
void test__exit() {long long start;printf("Testing _exit()...\n");start = get_time_us();printf("This is a test for _exit().\n"); // 輸出到緩沖區_exit(0); // 調用 _exit(),不會刷新緩沖區,也不會執行清理
}int main() {pid_t pid;int status;long long start, end;// 測試 exit()printf("Starting exit() test...\n");start = get_time_us();pid = fork();if (pid == 0) {test_exit(); // 子進程調用 exit()} else {waitpid(pid, &status, 0); // 等待子進程退出end = get_time_us();printf("Time taken by exit(): %lld us\n", end - start);}// 測試 _exit()printf("Starting _exit() test...\n");start = get_time_us();pid = fork();if (pid == 0) {test__exit(); // 子進程調用 _exit()} else {waitpid(pid, &status, 0); // 等待子進程退出end = get_time_us();printf("Time taken by _exit(): %lld us\n", end - start);}return 0;
}/*
環境:https://www.onlinegdb.com/
Starting exit() test...
Testing exit()...
This is a test for exit().
Cleanup function called.
Time taken by exit(): 276 us
Starting _exit() test...
Testing _exit()...
This is a test for _exit().
Time taken by _exit(): 182 us`_exit()` 比 `exit()` 耗時低的原因在于它們的功能和執行過程不同:*/
_exit()
比 exit()
耗時低的原因在于它們的功能和執行過程不同:
1. exit()
的行為
- 清理工作:
- 調用所有通過
atexit()
注冊的清理函數(如cleanup()
)。 - 刷新所有打開的文件緩沖區(確保緩沖區中的數據寫入文件)。
- 關閉所有打開的文件描述符。
- 調用所有通過
- 系統調用:
- 在完成上述清理工作后,
exit()
最終會調用_exit()
來終止進程。
- 在完成上述清理工作后,
由于 exit()
需要執行額外的清理工作,因此耗時更長。
2. _exit()
的行為
- 直接終止:
_exit()
是一個系統調用,它直接終止進程。- 不執行任何清理工作:
- 不調用通過
atexit()
注冊的清理函數。 - 不刷新文件緩沖區。
- 不關閉文件描述符。
- 不調用通過
- 更快:
- 因為
_exit()
跳過了所有清理步驟,直接讓操作系統回收資源,所以執行速度更快。
- 因為
3. 實驗結果分析
在您的實驗中:
exit()
耗時:276 微秒。_exit()
耗時:182 微秒。
這表明 exit()
的清理工作(如調用 cleanup()
和刷新緩沖區)增加了額外的時間開銷。
4. 影響耗時的因素
以下因素可能會影響 exit()
和 _exit()
的耗時差異:
- 清理函數的復雜度:
- 如果通過
atexit()
注冊了多個清理函數,exit()
的耗時會進一步增加。
- 如果通過
- 文件緩沖區大小:
- 如果有大量數據需要刷新到文件,
exit()
的耗時會顯著增加。
- 如果有大量數據需要刷新到文件,
- 系統性能:
- 系統的 I/O 性能和進程管理效率也會影響耗時。
5. 總結
exit()
慢:因為它執行了清理工作(如調用清理函數和刷新緩沖區)。_exit()
快:因為它直接終止進程,跳過了所有清理步驟。- 在子進程中,通常推薦使用
_exit()
,以避免重復清理父進程的資源。