C父子进程乒乓通信程序产生大量进程致Linux崩溃、磁盘占满如何解决?
问题背景
我编写了如下C语言程序,功能是实现父进程与子进程之间的“乒乓通信”。开发编译阶段我就发现电脑负载持续升高,但当时未重视,最终程序导致我的Linux系统崩溃,生成了大量异常进程拖慢整机运行速度,还产生了大量临时/日志文件,原本剩余35GB的磁盘仅剩200MB可用空间。
我需要解决以下问题:
- 如何修改程序避免其生成大量异常进程?
- 我已经尝试执行sudo apt autoremove、autoclean命令,还删除了/var/log目录下所有.gz后缀的文件,但磁盘剩余空间依然只有200MB,经查/var/log目录占用空间接近40GB,我不想删除该目录下的必要系统文件,该如何正确清理日志目录?
- 为什么我的程序会生成这么多临时文件或日志文件?
附问题代码
/******************************** Header Files ********************************/ #define _GNU_SOURCE #include <signal.h> #include <stdio.h> /* printf */ #include <stdlib.h> /* exit */ #include <unistd.h> /* fork, getpid, sleep */ #include <sys/wait.h> /* 回收子进程需要引入该头文件 */ /**************************** Forward Declarations ****************************/ /* exits the program with the given 'ret status' if 'is_bad' is true */ void ExitIfBad(int is_bad, char *msg_to_print, int ret_stat); void handle_siguser1(int signal_id); void handle_siguser2(int signal_id); void handle_sigint(int signal_id); enum {CHILD = 0}; static int is_parent_turn = 1; static pid_t global_pid; // 存储子进程pid用于退出时回收 /************************* Functions Implementations *************************/ int main() { /* create a child process */ pid_t pid = fork(); global_pid = pid; ExitIfBad(pid < 0, "Error: Could not create a process\n", 1); signal(SIGUSR1, handle_siguser1); signal(SIGUSR2, handle_siguser2); signal(SIGINT, handle_sigint); // 绑定终止信号处理逻辑 /* returned to the newly created child process. */ if (CHILD == pid) { while (1) { sleep(2); kill(getppid(), SIGUSR2); } } /* returned to parent */ else { while (1) { kill(getpid(), SIGUSR1); sleep(2); // 增加延迟,避免高频发信号 } } return 0; } /******************************************************************************/ void handle_siguser1(int signum) { if (is_parent_turn) { printf("\n\nPING\n\n"); is_parent_turn = 0; } } /******************************************************************************/ void handle_siguser2(int signum) { if (!is_parent_turn) { printf("\n\nPONG\n\n"); is_parent_turn = 1; } } /******************************************************************************/ void handle_sigint(int signum) { if (global_pid > 0) { kill(global_pid, SIGKILL); wait(NULL); // 回收子进程资源,避免孤儿进程残留 } exit(0); } /******************************************************************************/ void ExitIfBad(int is_bad, char *msg_to_print, int ret_stat) { if (is_bad) { puts(msg_to_print); exit(ret_stat); } } /******************************************************************************/
问题解答
1. 程序修改避免生成大量异常进程的方案
你原程序的核心问题有两个:一是父进程死循环无任何延迟,高频给自己发信号占满CPU;二是没有进程退出回收逻辑,父进程异常退出后子进程会变成孤儿进程反复运行,多启动几次就会残留大量异常进程。修改要点如下:
- 父进程发送信号后增加2秒延迟,和子进程的发送节奏匹配,避免CPU跑满
- 增加SIGINT信号处理逻辑,用户按Ctrl+C终止程序时,父进程主动杀死子进程并回收资源,不会残留孤儿进程
- 移除信号处理函数里的sleep调用,sleep属于不可重入函数,放在信号处理函数中会导致逻辑异常,直接把延迟逻辑移到主循环即可
2. /var/log目录正确清理方案
首先用命令du -h /var/log | sort -hr | head -20定位占用最高的前20个日志文件,再针对性处理:
- 不要直接删除正在被系统进程写入的大日志文件,直接删除不会释放文件句柄,空间不会回收,正确操作是用
> 日志文件路径清空内容,比如> /var/log/syslog、> /var/log/journal/xxxxxx/system.journal - 执行
sudo logrotate -f /etc/logrotate.conf强制触发系统自带的日志轮转,工具会自动压缩、删除过期日志,不会误删系统必要的日志文件 - 如果是journal日志占用过高,可以执行
sudo journalctl --vacuum-size=1G直接限制journal日志总大小为1G,自动清理旧日志 - 清理完成后执行
sudo sync刷新磁盘缓存,确认空间释放
3. 大量日志/临时文件生成原因
你的原程序父进程死循环无延迟,每秒可以触发上万次printf输出PING内容,所有的标准输出内容都会被系统日志服务(rsyslog/journald)收集写入/var/log目录下的日志文件,短时间内就能生成几十GB的日志,直接占满磁盘空间。
内容的提问来源于stack exchange,提问作者NoobCoder
相关产品推荐
相关产品推荐

