Linux

关注公众号 jb51net

关闭
首页 > 网站技巧 > 服务器 > Linux > Linux进程资源占用

Linux进程资源占用详解

作者:REDcker

本文档详细介绍了在Linux系统下分析和监控进程资源占用的方法,涵盖了多种工具和命令,如top、htop、ps、pidstat、atop、sar、vmstat、pmap、smem、ss、iotop、lsof等,这些工具可以帮助用户快速查看和监控CPU、内存、I/O等关键指标,从而有效定位和解决资源使用问题

Linux进程资源占用分析指南

本文档介绍在 Linux 系统下如何分析和监控进程的资源占用情况,包括 CPU、内存、I/O 等关键指标的查看方法。

快速开始

前提条件

已知进程 ID (PID)

获取 PID 的方法:

# 通过进程名查找
pgrep process_name
ps aux | grep process_name

# 通过端口查找
lsof -i :port
netstat -tlnp | grep :port

命令行工具

1.top命令(实时监控)

基本用法:

top -p PID

交互式操作:

输出说明:

2.htop(增强版 top,推荐)

基本用法:

htop -p PID

功能特点:

快捷键:

3.ps命令(快照查看)

基本资源查看:

ps -p PID -o pid,ppid,%cpu,%mem,vsz,rss,cmd

详细资源报告:

ps -p PID -o user,pid,ppid,ni,%cpu,%mem,vsz,rss,tty,stat,start,time,cmd,etime

字段说明:

连续监控:

watch -n 1 'ps -p PID -o pid,%cpu,%mem,vsz,rss,cmd'

4.pidstat(详细资源统计)

安装:

# Ubuntu/Debian
sudo apt-get install sysstat

# CentOS/RHEL
sudo yum install sysstat

基本用法:

# 每2秒刷新一次,共显示5次
pidstat -p PID 2 5

详细资源监控:

# 磁盘 I/O 统计
pidstat -d -p PID

# 内存页错误统计
pidstat -r -p PID

# 栈使用统计
pidstat -s -p PID

# 线程级统计
pidstat -t -p PID

# 综合统计(CPU、内存、I/O)
pidstat -u -r -d -p PID 2 5

输出指标:

5.atop(高级监控)

安装:

# Ubuntu/Debian
sudo apt-get install atop

# CentOS/RHEL
sudo yum install atop

基本用法:

atop -p PID

功能亮点:

快捷键:

6.nmon(可视化监控)

安装:

# Ubuntu/Debian
sudo apt-get install nmon

# CentOS/RHEL
sudo yum install nmon

基本用法:

nmon -p PID

交互式界面:

7.iotop(I/O 监控)

安装:

# Ubuntu/Debian
sudo apt-get install iotop

# CentOS/RHEL
sudo yum install iotop

基本用法:

# 实时监控指定进程的 I/O
iotop -p PID

# 显示累计 I/O
iotop -a -p PID

输出说明:

8.lsof(列出打开文件)

基本用法:

# 查看进程打开的所有文件
lsof -p PID

# 查看进程打开的网络连接
lsof -p PID -i

# 查看进程打开的文件描述符数量
lsof -p PID | wc -l

# 查看进程打开的具体文件类型
lsof -p PID | grep -E 'REG|DIR|CHR|FIFO|SOCK'

# 查看进程的端口占用
lsof -p PID -iTCP -sTCP:LISTEN

# 查看进程的工作目录
lsof -p PID | grep cwd

# 查看进程打开的文件并按类型统计
lsof -p PID | awk '{print $5}' | sort | uniq -c

字段说明:

9.sar(系统活动报告)

安装:

# Ubuntu/Debian
sudo apt-get install sysstat

# CentOS/RHEL
sudo yum install sysstat

基本用法:

# 查看当前 CPU 使用(每1秒刷新,共5次)
sar -u 1 5

# 查看内存使用
sar -r 1 5

# 查看 I/O 统计
sar -b 1 5

# 查看进程相关统计
sar -x PID 1 5

# 查看历史数据(需要启用 sysstat 数据收集)
sar -u
sar -r
sar -b

# 生成综合报告
sar -A > sar_report.txt

优势:

10.vmstat(虚拟内存统计)

基本用法:

# 每2秒刷新一次,共显示5次
vmstat 2 5

# 查看进程相关统计
vmstat -p /dev/sda1 2 5

# 显示详细的内存统计
vmstat -s

输出说明:

11.pmap(内存映射查看)

基本用法:

# 查看进程的内存映射
pmap -x PID

# 显示详细信息
pmap -XX PID

# 显示设备格式
pmap -d PID

# 显示扩展格式
pmap -X PID

# 查看内存映射摘要
pmap -q PID

输出说明:

用途:

12.smem(内存使用统计)

安装:

# Ubuntu/Debian
sudo apt-get install smem

# CentOS/RHEL
sudo yum install smem

基本用法:

# 查看进程内存使用(按 PSS 排序)
smem -P process_name

# 查看指定 PID 的内存使用
smem -p PID

# 显示详细统计
smem -t -k -p PID

# 按用户统计
smem -u

# 生成报告
smem -t -k -P process_name -c "pid user command pss rss"

优势:

13.ss(现代网络连接工具)

基本用法:

# 查看进程的网络连接
ss -tulpn | grep PID

# 查看 TCP 连接
ss -tpn | grep PID

# 查看 UDP 连接
ss -upn | grep PID

# 显示详细信息
ss -tulnap | grep PID

# 查看监听端口
ss -tlnp | grep PID

# 统计连接数
ss -s

相比 netstat 的优势:

14.time命令(执行时间统计)

基本用法:

# 使用 time 命令运行程序并统计资源
time command

# 使用 /usr/bin/time 获取更详细信息
/usr/bin/time -v command

# 查看进程运行时间
time -p sleep 5

# 详细资源统计
/usr/bin/time -f "%E real, %U user, %S sys, %M KB memory" command

输出说明:

15.taskset/numactl(CPU 亲和性和 NUMA)

基本用法:

# 查看进程的 CPU 亲和性
taskset -p PID

# 查看进程的 NUMA 节点
numactl --show

# 查看进程的 NUMA 统计
numastat -p PID

# 查看系统 NUMA 信息
numactl --hardware

用途:

16.prlimit(资源限制查看)

基本用法:

# 查看进程的资源限制
prlimit --pid=PID

# 查看特定资源限制
prlimit --pid=PID --as    # 虚拟内存限制
prlimit --pid=PID --rss   # 物理内存限制
prlimit --pid=PID --nofile # 文件描述符限制
prlimit --pid=PID --cpu   # CPU 时间限制

常用资源限制:

17.systemd-cgtop(systemd 进程组监控)

基本用法:

# 查看 systemd 管理的进程组资源使用
systemd-cgtop

# 查看特定服务的资源使用
systemd-cgtop /system.slice/service-name.service

# 查看用户服务的资源使用
systemd-cgtop /user.slice/user-1000.slice

适用场景:

18.slabtop(内核 slab 缓存监控)

基本用法:

# 实时查看内核 slab 缓存使用
slabtop

# 按使用量排序
slabtop -s c

# 只显示正在使用的缓存
slabtop -o

用途:

系统文件分析

/proc文件系统(底层信息)

/proc/PID/ 目录提供了进程的详细底层信息。

CPU 使用情况
# 查看进程 CPU 时间统计
cat /proc/PID/stat | awk '{print "用户态CPU: " $14 " 时钟周期"; print "内核态CPU: " $15 " 时钟周期"}'

# 实时监控 CPU 使用率
while true; do
  cat /proc/PID/stat | awk '{utime=$14; stime=$15; total=$14+$15; print "用户态: " utime " 内核态: " stime " 总计: " total}'
  sleep 1
done
内存使用情况
# 查看内存详细信息
cat /proc/PID/status | grep -E 'VmPeak|VmSize|VmRSS|VmSwap|VmHWM|VmData|VmStk|VmExe'

# 字段说明:
# VmPeak  - 虚拟内存峰值(KB)
# VmSize  - 当前虚拟内存大小(KB)
# VmRSS   - 实际物理内存使用(KB)
# VmSwap  - 交换分区使用(KB)
# VmHWM   - 物理内存峰值(KB)
# VmData  - 数据段大小(KB)
# VmStk   - 栈大小(KB)
# VmExe   - 可执行文件大小(KB)
打开文件描述符
# 查看打开的文件描述符数量
ls -l /proc/PID/fd | wc -l

# 查看具体打开的文件
ls -l /proc/PID/fd

# 查看打开的文件列表(带路径)
for fd in /proc/PID/fd/*; do
  readlink -f "$fd"
done
I/O 统计
# 查看 I/O 统计信息
cat /proc/PID/io

# 输出字段说明:
# rchar        - 读取字符数(包括缓存)
# wchar        - 写入字符数(包括缓存)
# syscr        - 系统调用读取次数
# syscw        - 系统调用写入次数
# read_bytes   - 实际磁盘读取字节数
# write_bytes  - 实际磁盘写入字节数
# cancelled_write_bytes - 取消的写入字节数
线程信息
# 查看线程数量
ls /proc/PID/task | wc -l

# 查看每个线程的详细信息
for tid in /proc/PID/task/*; do
  echo "线程 ID: $(basename $tid)"
  cat $tid/stat | awk '{print "CPU时间: " $14+$15}'
done
上下文切换
# 查看上下文切换统计
cat /proc/PID/status | grep -E 'voluntary_ctxt_switches|nonvoluntary_ctxt_switches'

# 字段说明:
# voluntary_ctxt_switches     - 自愿上下文切换(等待资源)
# nonvoluntary_ctxt_switches  - 非自愿上下文切换(时间片到期)
网络连接
# 查看进程的网络连接
cat /proc/PID/net/tcp
cat /proc/PID/net/udp

# 或使用 netstat/lsof
netstat -anp | grep PID
lsof -p PID -i
资源限制
# 查看进程的资源限制
cat /proc/PID/limits

# 字段说明:
# Limit           - 资源类型
# Soft Limit      - 软限制(可超过但会收到信号)
# Hard Limit      - 硬限制(不可超过)
# Units           - 单位
环境变量
# 查看进程的环境变量
cat /proc/PID/environ | tr '\0' '\n'

# 查找特定环境变量
cat /proc/PID/environ | tr '\0' '\n' | grep VARIABLE_NAME
命令行和工作目录
# 查看命令行参数
cat /proc/PID/cmdline | tr '\0' ' '

# 查看工作目录
readlink /proc/PID/cwd

# 查看可执行文件路径
readlink /proc/PID/exe
内存映射详情
# 查看详细的内存映射
cat /proc/PID/maps

# 查看内存映射摘要
cat /proc/PID/smaps

# smaps 提供更详细的信息:
# - 每个映射区域的详细统计
# - 共享/私有内存大小
# - 脏页统计
# - 交换分区使用
进程关系
# 查看进程树
pstree -p PID

# 查看子进程
ps --ppid PID

# 查看进程会话和进程组
cat /proc/PID/stat | awk '{print "会话ID: " $6 " 进程组: " $5}'

Cgroup 资源监控

Cgroup v1 文件系统

如果进程在 cgroup 中运行(如 Docker 容器、systemd 服务),可以通过 cgroup 文件系统查看资源使用:

# 查找进程的 cgroup 路径
cat /proc/PID/cgroup

# 查看 CPU 使用(如果使用 CPU cgroup)
cat /sys/fs/cgroup/cpu/cgroup_name/cpuacct.usage
cat /sys/fs/cgroup/cpu/cgroup_name/cpu.stat

# 查看内存使用(如果使用 Memory cgroup)
cat /sys/fs/cgroup/memory/cgroup_name/memory.usage_in_bytes
cat /sys/fs/cgroup/memory/cgroup_name/memory.stat
cat /sys/fs/cgroup/memory/cgroup_name/memory.limit_in_bytes

# 查看 I/O 统计(如果使用 blkio cgroup)
cat /sys/fs/cgroup/blkio/cgroup_name/blkio.io_service_bytes
cat /sys/fs/cgroup/blkio/cgroup_name/blkio.io_serviced

# 查看进程数限制
cat /sys/fs/cgroup/pids/cgroup_name/pids.current
cat /sys/fs/cgroup/pids/cgroup_name/pids.max

Cgroup v2 文件系统

现代 Linux 系统使用 cgroup v2:

# 查找进程的 cgroup 路径
cat /proc/PID/cgroup

# 查看资源统计(统一接口)
cat /sys/fs/cgroup/cgroup_name/cpu.stat
cat /sys/fs/cgroup/cgroup_name/memory.current
cat /sys/fs/cgroup/cgroup_name/memory.stat
cat /sys/fs/cgroup/cgroup_name/io.stat

# 查看资源限制
cat /sys/fs/cgroup/cgroup_name/memory.max
cat /sys/fs/cgroup/cgroup_name/cpu.max

systemd 服务资源监控

# 查看服务的资源使用
systemd-cgtop

# 查看特定服务的统计
systemctl status service-name
systemd-cgtop /system.slice/service-name.service

# 查看服务资源限制配置
systemctl show service-name | grep -i limit

Docker 容器资源监控

# 查看容器的资源使用
docker stats container_name

# 查看容器的详细资源统计
docker stats --no-stream container_name

# 查看容器的 cgroup 信息
docker inspect container_name | grep -i cgroup

# 进入容器查看
docker exec container_name cat /proc/self/cgroup

高级监控工具

bpftrace(动态追踪)

安装:

# Ubuntu 20.04+
sudo apt-get install bpftrace

# 或从源码编译

基本用法:

# 实时监控 CPU 使用(按用户态堆栈)
bpftrace -e 'profile:hz:99 /pid == PID/ { @[ustack] = count(); }'

# 监控系统调用
bpftrace -e 'tracepoint:syscalls:sys_enter_* /pid == PID/ { @[probe] = count(); }'

# 监控 I/O 操作
bpftrace -e 'tracepoint:block:block_rq_issue /pid == PID/ { @[comm] = count(); }'

# 监控内存分配
bpftrace -e 'uprobe:/lib/x86_64-linux-gnu/libc.so.6:malloc /pid == PID/ { @[ustack] = count(); }'

perf(性能分析)

安装:

# Ubuntu/Debian
sudo apt-get install linux-perf

# CentOS/RHEL
sudo yum install perf

基本用法:

# 实时查看热点函数
perf top -p PID

# 记录性能数据
perf record -p PID -g sleep 10

# 查看报告
perf report

# 统计系统调用
perf stat -p PID sleep 5

# 追踪特定事件
perf trace -p PID

strace(系统调用追踪)

基本用法:

# 追踪系统调用并统计
strace -cp PID

# 追踪特定系统调用
strace -e trace=open,read,write -p PID

# 显示时间戳
strace -t -p PID

# 统计系统调用耗时
strace -c -p PID

关键指标说明

指标对照表

指标命令/文件说明正常范围参考
CPU 使用ps -o %cpu进程占用 CPU 百分比0-100%
内存使用ps -o %mem,rss,vsz%mem=物理内存百分比,rss=实际物理内存(KB),vsz=虚拟内存大小(KB)根据系统内存调整
线程数ls /proc/PID/task任务目录数量即为线程数根据应用类型
I/O 读取/proc/PID/ioread_bytes 显示实际磁盘读取根据应用需求
I/O 写入/proc/PID/iowrite_bytes 显示实际磁盘写入根据应用需求
上下文切换/proc/PID/statusvoluntary_ctxt_switches/nonvoluntary_ctxt_switches过高可能存在问题
运行时间ps -o etime进程已运行时间 (格式: [[DD-]hh:]mm:ss)-
文件描述符ls /proc/PID/fd打开的文件描述符数量注意是否有泄漏

内存相关指标详解

CPU 相关指标详解

常见问题排查

1. CPU 使用率过高

诊断步骤:

# 查看 CPU 热点函数
perf top -p PID

# 统计系统调用
strace -cp PID

# 查看线程 CPU 使用
top -H -p PID

# 使用 bpftrace 追踪
bpftrace -e 'profile:hz:99 /pid == PID/ { @[ustack] = count(); }'

可能原因:

2. 内存使用过高

诊断步骤:

# 查看详细内存映射
pmap -x PID

# 查看内存使用趋势
watch -n 1 'ps -p PID -o pid,%mem,rss,vsz'

# 使用 gdb 查看内存区域
gdb -p PID -ex "info proc mappings" --batch

# 检查内存泄漏(需要持续监控)
valgrind --leak-check=full ./program

可能原因:

3. I/O 瓶颈

诊断步骤:

# 实时监控 I/O
iotop -p PID

# 查看 I/O 统计
cat /proc/PID/io

# 使用 SystemTap 追踪文件操作(需要 root)
stap -e 'probe vfs.* { if (pid() == PID) printf("%s\n", pp()) }'

# 查看磁盘使用情况
iostat -x 1

可能原因:

4. 线程/进程过多

诊断步骤:

# 查看线程数量
ls /proc/PID/task | wc -l

# 查看线程详情
ps -T -p PID

# 查看进程树
pstree -p PID

5. 文件描述符泄漏

诊断步骤:

# 监控文件描述符数量
watch -n 1 'ls /proc/PID/fd | wc -l'

# 查看打开的文件
lsof -p PID

# 查看具体文件类型分布
ls -l /proc/PID/fd | awk '{print $NF}' | xargs -I {} readlink {} | sort | uniq -c

自动化监控脚本

综合监控脚本

创建一个综合监控脚本,定期采集进程的各项资源指标:

#!/bin/bash

# 进程资源监控脚本
# 用法: ./monitor_process.sh <PID> [interval] [count]

if [ -z "$1" ]; then
  echo "用法: $0 <PID> [刷新间隔(秒)] [监控次数]"
  echo "示例: $0 12345 2 10"
  exit 1
fi

PID=$1
INTERVAL=${2:-2}
COUNT=${3:-5}

# 检查进程是否存在
if ! kill -0 $PID 2>/dev/null; then
  echo "错误: 进程 $PID 不存在"
  exit 1
fi

echo "===== 进程 $PID 资源监控 (每 ${INTERVAL} 秒刷新,共 ${COUNT} 次) ====="
echo ""

for i in $(seq 1 $COUNT); do
  echo "--- 第 $i 次监控 ($(date '+%Y-%m-%d %H:%M:%S')) ---"
  
  # 基本信息
  echo "【基本信息】"
  ps -p $PID -o user,pid,ppid,ni,%cpu,%mem,vsz,rss,tty,stat,start,time,cmd --no-headers 2>/dev/null || echo "进程已结束"
  
  # CPU 使用
  if [ -f /proc/$PID/stat ]; then
    echo -e "\n【CPU 使用】"
    cat /proc/$PID/stat | awk '{
      utime = $14
      stime = $15
      cutime = $16
      cstime = $17
      total = utime + stime + cutime + cstime
      printf "用户态CPU: %d 时钟周期\n", utime
      printf "内核态CPU: %d 时钟周期\n", stime
      printf "子进程用户态: %d 时钟周期\n", cutime
      printf "子进程内核态: %d 时钟周期\n", cstime
      printf "总CPU时间: %d 时钟周期\n", total
    }'
  fi
  
  # 内存使用
  if [ -f /proc/$PID/status ]; then
    echo -e "\n【内存使用】"
    grep -E 'VmPeak|VmSize|VmRSS|VmSwap|VmHWM|VmData|VmStk|VmExe' /proc/$PID/status
  fi
  
  # I/O 统计
  if [ -f /proc/$PID/io ]; then
    echo -e "\n【I/O 统计】"
    cat /proc/$PID/io
  fi
  
  # 打开文件描述符
  if [ -d /proc/$PID/fd ]; then
    echo -e "\n【打开文件描述符数量】"
    echo "$(ls -l /proc/$PID/fd 2>/dev/null | wc -l) 个"
  fi
  
  # 线程数
  if [ -d /proc/$PID/task ]; then
    echo -e "\n【线程数】"
    echo "$(ls /proc/$PID/task 2>/dev/null | wc -l) 个"
  fi
  
  # 上下文切换
  if [ -f /proc/$PID/status ]; then
    echo -e "\n【上下文切换】"
    grep -E 'voluntary_ctxt_switches|nonvoluntary_ctxt_switches' /proc/$PID/status
  fi
  
  echo ""
  echo "=========================================="
  echo ""
  
  if [ $i -lt $COUNT ]; then
    sleep $INTERVAL
  fi
done

echo "监控完成"

保存监控数据脚本

#!/bin/bash

# 将监控数据保存到文件
# 用法: ./save_monitor.sh <PID> <output_file> [interval]

PID=$1
OUTPUT=${2:-"monitor_${PID}_$(date +%Y%m%d_%H%M%S).log"}
INTERVAL=${3:-5}

echo "开始监控进程 $PID,数据保存到 $OUTPUT"
echo "监控间隔: ${INTERVAL} 秒,按 Ctrl+C 停止"

while true; do
  TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
  
  # 检查进程是否存在
  if ! kill -0 $PID 2>/dev/null; then
    echo "[$TIMESTAMP] 进程已结束" >> "$OUTPUT"
    break
  fi
  
  # 采集数据
  {
    echo "===== $TIMESTAMP ====="
    ps -p $PID -o pid,%cpu,%mem,vsz,rss,cmd --no-headers
    [ -f /proc/$PID/status ] && grep -E 'VmRSS|VmSize' /proc/$PID/status
    [ -f /proc/$PID/io ] && cat /proc/$PID/io
    echo ""
  } >> "$OUTPUT"
  
  sleep $INTERVAL
done

echo "监控数据已保存到 $OUTPUT"

工具选择建议

根据不同场景选择合适的工具:

场景推荐工具说明
快速查看ps简单快速,适合脚本集成
实时监控htop 或 top交互式界面,适合手动监控
详细统计pidstat适合定期采样和数据分析
历史数据sar查看历史性能数据,适合趋势分析
I/O 分析iotop专门用于 I/O 监控
内存分析pmap、smempmap 查看内存映射,smem 提供更准确的内存统计
网络连接ss、lsofss 更现代快速,lsof 功能更全面
文件描述符lsof查看进程打开的文件和网络连接
综合监控atop功能全面,适合系统管理员
性能分析perf 或 bpftrace适合深度性能调优
系统调用strace追踪和统计系统调用
资源限制prlimit查看和设置进程资源限制
CPU 亲和性taskset、numactl查看和设置 CPU 绑定和 NUMA
容器监控docker stats、cgroup监控容器资源使用
systemd 服务systemd-cgtop监控 systemd 管理的服务
自动化/proc 文件系统适合脚本和自动化工具
问题排查strace + perf + pmap综合工具定位性能问题

总结:分析 Linux 进程资源占用有多种方法,选择合适的工具可以事半功倍:

常用方法分类

日常监控

专项分析

脚本集成

性能分析

容器和服务监控

系统级监控

关键指标

最佳实践

  1. 定期监控:建立监控机制,定期采集关键指标
  2. 建立基线:记录正常情况下的资源使用,便于对比
  3. 组合使用:根据问题类型组合使用多个工具
  4. 自动化:使用脚本自动化监控和告警
  5. 历史数据:启用 sar 数据收集,便于问题回溯
  6. 容器环境:在容器环境中使用 cgroup 相关工具

问题排查流程

  1. 快速定位:使用 htoptop 快速查看资源占用
  2. 详细分析:使用 pidstatpmap 等工具深入分析
  3. 性能分析:使用 perfstrace 定位性能瓶颈
  4. 历史对比:使用 sar 查看历史数据,分析趋势
  5. 综合诊断:结合多个工具的结果,全面分析问题

定期监控和记录这些指标,有助于及时发现和解决性能问题。根据具体场景选择合适的工具组合,可以更高效地完成资源分析和问题排查。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文