Linux: 进程管理——ps / top / kill 与系统监控

在 Linux 上,运行中的程序叫进程(Process)。管理进程——查看谁在跑、占了多少资源、如何优雅地停止它——是服务器管理的核心技能。

📋 前置知识:需要先掌握以下内容

1. 你将学到


2. 一个服务起不来的故事

(1) 痛点:端口被占用了

小明启动 Node.js 服务时遇到:

BASH
node server.js
# Error: listen EADDRINUSE: address already in use :::3000

端口被占用了。他不知道是哪个进程占用了 3000 端口,也不知道怎么让它停下来。

(2) 定位并释放端口

BASH
# 找到占用 3000 端口的进程
ss -tlnp | grep 3000
# LISTEN 0 128 *:3000 *:* users:(("node",pid=1234,fd=20))

# 终止进程
kill 1234

# 重新启动服务
node server.js

(3) 收益:解决了端口冲突

小明学会了用 sslsof 找到占用端口的进程、用 kill 发送信号终止进程。之后遇到端口冲突 30 秒内解决。


3. 知识点讲解

(1) ps——进程快照

BASH
# 核心用法
ps aux               # 所有进程的详细信息
ps aux | grep nginx  # 过滤特定进程
ps -ef               # 标准格式

# 常用字段含义
# USER    PID  %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
# alice  1234  0.3  1.2 123456 54321 ?        Ssl  10:23   0:01 node server.js

# 自定义输出
ps -eo pid,user,%cpu,%mem,comm --sort=-%cpu | head -10
字段 含义
PID 进程 ID
PPID 父进程 ID
%CPU CPU 占用百分比
%MEM 内存占用百分比
VSZ 虚拟内存大小(KB)
RSS 物理内存大小(KB)
STAT 进程状态(R=运行、S=睡眠、D=不可中断、Z=僵尸、T=停止)
START 启动时间
TIME 累计 CPU 时间
COMMAND 命令名 / 命令行

(2) top/htop——实时监控

TEXT 📖 仅展示
top                             # 启动 top
top -o %MEM                     # 按内存排序
top -u alice                    # 只看特定用户进程
top -bn1 | head -20             # 一次性输出

# top 运行中的快捷键
# P    按 CPU 排序
# M    按内存排序
# k    终止进程(会提示输入 PID)
# u    过滤用户
# q    退出 top

# htop 是 top 的增强版(更美观,支持鼠标)
htop

(3) kill——发送信号

BASH
kill PID                        # 发送 SIGTERM(15),请求终止
kill -2 PID                     # 发送 SIGINT(2),相当于 Ctrl+C
kill -9 PID                     # 发送 SIGKILL(9),强制终止
kill -1 PID                     # 发送 SIGHUP(1),重载配置
kill -19 PID                    # 发送 SIGSTOP(19),暂停进程
kill -18 PID                    # 发送 SIGCONT(18),恢复进程

# 按名称杀进程
pkill -f "node server.js"       # 匹配命令行
killall nginx                   # 杀所有同名进程
信号 编号 含义
SIGHUP 1 挂起(重载配置)
SIGINT 2 中断(Ctrl+C)
SIGQUIT 3 退出(带 core dump)
SIGKILL 9 强制杀死(不能捕获/忽略)
SIGTERM 15 请求终止(默认)
SIGSTOP 19 暂停(不能捕获/忽略)
SIGCONT 18 继续执行

核心原则:kill PID(SIGTERM),不行再用 kill -9 PID(SIGKILL)。SIGKILL 不给进程清理机会,可能导致数据丢失。

⚠️ 注意kill -9(SIGKILL)强制终止进程,不给它任何清理机会——打开的文件可能损坏、数据库事务可能中断、临时文件不会删除。只在 kill PID(SIGTERM)无响应时才使用 -9,绝不能图省事直接用。

(4) 后台运行

TEXT 📖 仅展示
# &——放入后台
node server.js &                 # 启动后立即返回终端

> 💡 **提示**:命令末尾加 `&` 可以让它在后台运行,立即释放终端。但 `&` 单独使用时,关闭终端会话后进程也会被终止。要使进程在终端关闭后继续运行,需要搭配 `nohup`:`nohup command &`。
sleep 30 &                       # 后台运行 sleep

# jobs/fg/bg——管理后台任务
jobs                            # 查看后台任务列表
# [1]+  Running                 node server.js &
# [2]-  Running                 sleep 30 &
fg %1                          # 将任务 1 切到前台
bg %2                          # 将暂停的任务 2 放到后台继续

# Ctrl+Z——暂停当前前台任务并放入后台
# Ctrl+C——终止前台任务

# nohup——终端关闭后继续运行
nohup node server.js &
nohup python app.py > app.log 2>&1 &

> ℹ️ **说明**:`nohup` + `&` 是让命令在后台持久运行的标准组合——`nohup` 忽略 SIGHUP 信号(终端关闭时发出的信号),`&` 放入后台。输出默认写入 `nohup.out`,建议手动指定日志文件:`nohup command > app.log 2>&1 &`。

▶ 示例:查看进程

BASH
# 查看所有进程
ps aux | head -10

# 查看特定用户的进程
ps -u alice -o pid,%cpu,%mem,comm

# 按 CPU 使用率排序的前 10 个进程
ps aux --sort=-%cpu | head -11

# 查看进程树
ps auxf | head -20

输出:

TEXT 📖 仅展示
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1 169344 13224 ?        Ss   10:00   0:02 /sbin/init
root         2  0.0  0.0      0     0 ?        S    10:00   0:00 [kthreadd]
alice     1234  0.3  1.2 123456 54321 ?        Ssl  10:23   0:01 node server.js
alice     2345  0.0  0.0   2345   567 pts/0    S+   10:30   0:00 ps aux
PID   USER     %CPU  %MEM  COMMAND
1234  alice    0.3   1.2   node
5678  bob      0.1   0.5   python3
USER   PID %CPU %MEM  COMMAND
root   1   0.0  0.1   /sbin/init
root   456 0.5  2.1   /usr/bin/containerd
alice  1234 8.2  3.4   node server.js
bob    2345 5.1  4.2   python train.py

▶ 示例:实时监控

TEXT 📖 仅展示
# 启动 top
top

# top 内的操作
# P → 按 CPU 排序
# M → 按内存排序
# k → 输入 PID 后回车,输入信号号(15 或 9)回车
# q → 退出

# 非交互模式
top -bn1 | head -15

输出:

TEXT 📖 仅展示
top - 10:30:01 up  5:23,  2 users,  load average: 0.15, 0.10, 0.05
Tasks: 120 total,   1 running, 119 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.3 us,  0.8 sy,  0.0 ni, 96.5 id,  0.2 wa,  0.0 hi,  0.2 si
MiB Mem :   3936.0 total,    512.0 free,   2048.0 used,   1376.0 buff/cache

▶ 示例:终止进程

BASH
# 启动一个后台进程
sleep 1000 &

# 找到它
ps aux | grep "sleep 1000"
# alice  5678  0.0  0.0   1234   567 pts/0    S    10:23   0:00 sleep 1000

# 优雅终止
kill 5678

# 如果不行
kill -9 5678

输出:

TEXT 📖 仅展示
[1]+  Terminated              sleep 1000
alice  5678  0.0  0.0   1234   567 pts/0    S    10:23   0:00 sleep 1000
[1]+  Killed                  sleep 1000

▶ 示例:后台运行实战

BASH
# 启动一个长时间运行的任务
nohup python train_model.py > train.log 2>&1 &

# 查看日志
tail -f train.log

# 即使关闭终端,train_model.py 也会继续运行
# 重新登录后用 ps aux 可以看到它还在

输出:

TEXT 📖 仅展示
[1] 5678
[2026-07-07 10:23:01] Training epoch 1/100...
[2026-07-07 10:23:15] Loss: 0.5234
[2026-07-07 10:23:30] Training epoch 2/100...

▶ 示例:nice/renice 调整优先级

TEXT 📖 仅展示
# nice 范围:-20(最高优先级)到 19(最低优先级)

# 以较低优先级启动
nice -n 10 ./heavy-task

# 调整已有进程的优先级
renice -n 5 -p 1234

# 查看进程的 nice 值
ps -eo pid,nice,comm | head -10

▶ 综合示例:服务管理

BASH
#!/bin/bash
# manage-server.sh - 管理 Node.js 应用

APP_NAME="server.js"
APP_DIR="/home/alice/app"
PID_FILE="/tmp/app.pid"

start() {
    if [ -f "$PID_FILE" ] && kill -0 $(cat "$PID_FILE") 2>/dev/null; then
        echo "应用已在运行 (PID: $(cat $PID_FILE))"
        exit 1
    fi
    cd "$APP_DIR"
    nohup node "$APP_NAME" > app.log 2>&1 &
    echo $! > "$PID_FILE"
    echo "应用已启动 (PID: $!)"
}

stop() {
    if [ ! -f "$PID_FILE" ]; then
        echo "应用未运行"
        exit 1
    fi
    PID=$(cat "$PID_FILE")
    echo "停止应用 (PID: $PID)..."
    kill "$PID" 2>/dev/null
    sleep 2
    if kill -0 "$PID" 2>/dev/null; then
        echo "强制终止..."
        kill -9 "$PID" 2>/dev/null
    fi
    rm -f "$PID_FILE"
    echo "已停止"
}

status() {
    if [ -f "$PID_FILE" ] && kill -0 $(cat "$PID_FILE") 2>/dev/null; then
        echo "运行中 (PID: $(cat $PID_FILE))"
        ps -p $(cat "$PID_FILE") -o pid,%cpu,%mem,etime,comm
    else
        echo "未运行"
    fi
}

case "${1:-status}" in
    start) start ;;
    stop) stop ;;
    restart) stop; start ;;
    *) status ;;
esac

❓ 常见问题

Q: kill -9 为什么不安全? A: \1

Q: 僵尸进程(Zombie)是什么? A: 进程已终止但父进程没有读取其退出状态。它在进程表中留下一个"僵尸"条目(STAT=Z)。Zombie 本身不占资源,但太多会耗尽进程表。通常需要杀掉或重启父进程来清理。

Q: nohup 和 disown 有什么区别? A: nohup 在启动时就设置进程忽略 SIGHUP 信号(终端关闭时触发)。disown 是 bash 内建命令,将已启动的任务从 Shell 的任务表中移除。nohup command & 是最常用的做法。

Q: 怎么限制一个进程的 CPU 使用率? A:cpulimit 工具:cpulimit -l 50 -p PID 限制为 50% CPU。或用 nice 降低优先级。Docker 容器中可以用 --cpus 限制。

Q: 怎么找到哪个进程占用了特定端口? A:ss -tlnp | grep :PORT(推荐)或 lsof -i :PORT(需安装 lsof)或 fuser PORT/tcp


📖 小节


📝 作业

  1. 基础题(难度⭐):用 ps aux --sort=-%cpu 找出 CPU 占用最高的 3 个进程,然后启动 sleep 300 &,用 jobs 查看并用 kill 终止
  2. 进阶题(难度⭐⭐):用 nohup 启动一个长时间运行的命令,关闭终端后重新打开验证它还在运行,然后用 ss -tlnp 查看本机所有监听端口及对应的进程
  3. 挑战题(难度⭐⭐⭐):写一个进程管理脚本,支持 start/stop/status/restart 四个命令,使用 PID 文件跟踪进程,并实现优雅终止(先 SIGTERM,等待 3 秒后 SIGKILL)
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏