当前位置: 首页 > article >正文

linux僵尸线程清理


文章目录

    • 1.cleanup_zombies.sh脚本
    • 2.terminate_zombie_parents.sh:
    • 3.监控僵尸进程monitor_zombies.sh:
    • 4. 执行权限
    • 5.定时处理
    • 6.使用go执行


1.cleanup_zombies.sh脚本

#!/bin/bash

echo "检测并尝试清理僵尸进程..."

# 查找所有僵尸进程及其父进程
zombies=$(ps -eo pid,ppid,stat,cmd | grep 'Z' | awk '$3 ~ /Z/ {print $1","$2}')
if [ -z "$zombies" ]; then
  echo "没有检测到僵尸进程!"
  exit 0
fi

echo "发现以下僵尸进程:"
echo "$zombies" | tr ',' '\t' | awk '{printf "僵尸PID: %s 父进程PID: %s\n", $1, $2}'

# 遍历每个僵尸进程
echo "$zombies" | while IFS=',' read -r zombie_pid parent_pid; do
  echo "尝试处理父进程 $parent_pid..."
  
  # 向父进程发送 SIGCHLD 信号,通知其处理僵尸
  kill -SIGCHLD "$parent_pid" 2>/dev/null
  
  # 检查父进程是否仍在运行
  if ps -p "$parent_pid" > /dev/null 2>&1; then
    echo "父进程 $parent_pid 仍在运行,可能需要手动检查。"
  else
    echo "父进程 $parent_pid 不存在,僵尸进程 $zombie_pid 将被 init 清理。"
  fi
done

echo "僵尸进程清理完成。"

2.terminate_zombie_parents.sh:

#!/bin/bash

echo "检测并尝试终止僵尸进程的父进程..."

# 查找所有僵尸进程及其父进程
zombies=$(ps -eo pid,ppid,stat,cmd | grep 'Z' | awk '$3 ~ /Z/ {print $1","$2}')
if [ -z "$zombies" ]; then
  echo "没有检测到僵尸进程!"
  exit 0
fi

echo "发现以下僵尸进程:"
echo "$zombies" | tr ',' '\t' | awk '{printf "僵尸PID: %s 父进程PID: %s\n", $1, $2}'

# 遍历每个僵尸进程
echo "$zombies" | while IFS=',' read -r zombie_pid parent_pid; do
  echo "尝试终止父进程 $parent_pid..."

  # 杀死父进程
  kill -9 "$parent_pid" 2>/dev/null

  if [ $? -eq 0 ]; then
    echo "父进程 $parent_pid 已终止,僵尸进程 $zombie_pid 将被系统清理。"
  else
    echo "无法终止父进程 $parent_pid,请手动检查。"
  fi
done

echo "父进程终止完成,僵尸进程将被清理。"

3.监控僵尸进程monitor_zombies.sh:

#!/bin/bash

logfile="/var/log/zombie_cleanup.log"
echo "[$(date)] 开始检测僵尸进程..." >> "$logfile"

# 查找僵尸进程
zombies=$(ps -eo pid,ppid,stat,cmd | grep 'Z' | awk '$3 ~ /Z/ {print $1","$2}')
if [ -z "$zombies" ]; then
  echo "[$(date)] 没有僵尸进程。" >> "$logfile"
  exit 0
fi

echo "[$(date)] 发现以下僵尸进程:" >> "$logfile"
echo "$zombies" | tr ',' '\t' | awk '{printf "僵尸PID: %s 父进程PID: %s\n", $1, $2}' >> "$logfile"

# 尝试清理
echo "$zombies" | while IFS=',' read -r zombie_pid parent_pid; do
  echo "[$(date)] 尝试处理父进程 $parent_pid..." >> "$logfile"
  kill -SIGCHLD "$parent_pid" 2>/dev/null
  
  if ! ps -p "$parent_pid" > /dev/null 2>&1; then
    echo "[$(date)] 父进程 $parent_pid 不存在,僵尸进程 $zombie_pid 将被系统清理。" >> "$logfile"
  else
    echo "[$(date)] 父进程 $parent_pid 仍在运行,请手动检查。" >> "$logfile"
  fi
done

echo "[$(date)] 僵尸清理完成。" >> "$logfile"

4. 执行权限

chmod +x cleanup_zombies.sh
chmod +x terminate_zombie_parents.sh
chmod +x monitor_zombies.sh

5.定时处理

运行 :手动清理僵尸:./cleanup_zombies.sh 强制终止父进程;
bash 定期监控(结合 cron 使用): 将 monitor_zombies.sh 添加到 cron,每分钟运行一次:
crontab -e  * * * * * /path/to/monitor_zombies.sh

6.使用go执行

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strings"
)

// ZombieProcess 结构体用于存储僵尸进程的 PID 和父进程的 PPID
type ZombieProcess struct {
	PID  string
	PPID string
}

func main() {
	fmt.Println("检测并尝试清理僵尸进程...")

	// 第一步:查找僵尸进程
	zombies, err := findZombies()
	if err != nil {
		fmt.Printf("无法检测僵尸进程: %v\n", err)
		return
	}

	// 如果没有僵尸进程
	if len(zombies) == 0 {
		fmt.Println("没有检测到僵尸进程!")
		return
	}

	// 输出检测到的僵尸进程信息
	fmt.Println("发现以下僵尸进程:")
	for _, z := range zombies {
		fmt.Printf("僵尸PID: %s 父进程PID: %s\n", z.PID, z.PPID)
	}

	// 第二步:尝试清理每个僵尸进程
	for _, z := range zombies {
		fmt.Printf("尝试通知父进程 %s 清理僵尸进程 %s...\n", z.PPID, z.PID)
		err := notifyParent(z.PPID) // 通知父进程
		if err != nil {
			fmt.Printf("无法通知父进程 %s: %v\n", z.PPID, err)
			continue
		}

		// 第三步:验证父进程是否仍然活跃
		if isParentActive(z.PPID) {
			fmt.Printf("父进程 %s 仍在运行,请手动检查。\n", z.PPID)
		} else {
			fmt.Printf("父进程 %s 不存在,僵尸进程 %s 将由系统清理。\n", z.PPID, z.PID)
		}
	}

	fmt.Println("僵尸进程清理完成。")
}

// findZombies 使用 `ps` 命令查找僵尸进程
func findZombies() ([]ZombieProcess, error) {
	// 执行 ps 命令,列出所有进程的 PID, PPID 和状态
	cmd := exec.Command("ps", "-eo", "pid,ppid,stat")
	output, err := cmd.Output()
	if err != nil {
		return nil, fmt.Errorf("执行 ps 命令失败: %w", err)
	}

	// 用于存储检测到的僵尸进程
	var zombies []ZombieProcess
	scanner := bufio.NewScanner(bytes.NewReader(output))
	for scanner.Scan() {
		line := scanner.Text()
		fields := strings.Fields(line)

		// 检查进程状态是否为 'Z'(僵尸进程)
		if len(fields) >= 3 && strings.Contains(fields[2], "Z") {
			zombies = append(zombies, ZombieProcess{
				PID:  fields[0], // 僵尸进程的 PID
				PPID: fields[1], // 僵尸进程的父进程 ID
			})
		}
	}

	if err := scanner.Err(); err != nil {
		return nil, fmt.Errorf("解析 ps 命令输出失败: %w", err)
	}

	return zombies, nil
}

// notifyParent 向父进程发送 SIGCHLD 信号,通知其处理僵尸进程
func notifyParent(ppid string) error {
	// 使用 kill 命令发送 SIGCHLD 信号
	cmd := exec.Command("kill", "-SIGCHLD", ppid)
	err := cmd.Run()
	if err != nil {
		return fmt.Errorf("发送 SIGCHLD 失败: %w", err)
	}
	return nil
}

// isParentActive 检查父进程是否仍然活跃
func isParentActive(ppid string) bool {
	// 使用 ps 命令检查父进程是否存在
	cmd := exec.Command("ps", "-p", ppid)
	err := cmd.Run()
	return err == nil
}


http://www.kler.cn/a/410554.html

相关文章:

  • 滑动窗口最大值(java)
  • Spring Boot 3.0废弃了JavaEE,改用了Jakarta EE
  • [每日一氵] 拆分 pip install git+https://github.com/xxx/xx.git@bece3d4
  • 001 MATLAB介绍
  • Java基础1.0
  • 使用LLaMA-Factory微调时的数据集选择
  • 【Redis 缓存策略】更新、穿透、雪崩、击穿、布隆过滤
  • C语言-数学基础问题
  • ArcGIS API for Javascript学习
  • git 命令之只提交文件的部分更改
  • Python多进程与多线程详解:全面指南
  • 硬中断关闭后的堆栈抓取方法
  • HarmonyOS4+NEXT星河版入门与项目实战(19)------状态管理 @Prop@Link@Provide@Consume
  • nodejs操作selenium-webdriver
  • HashMap的寻址算法(源码分析)
  • 路由器中继与桥接
  • WPF中如何让Textbox显示为一条直线
  • Kali Linux语言设置成中文
  • 硬盘(HDD)与固态硬盘(SSD)详细解读
  • WSL安装不同版本ubuntu(已有ubuntu20.04,再装ubuntu18.04)
  • Linux(Ubuntu)升级openssh至9.6版本
  • PyTorch2
  • 树链剖分(重链剖分)
  • ES实用面试题
  • 什么是 C++ 中的类型别名和 using 声明? 如何使用类型别名和 using 声明?
  • 三维测量与建模笔记 - 点特征提取 - 4.5 SURF-FAST-ORB