Linux /proc 文件系统实战:手动计算 top 命令 3 大核心指标(CPU%、MEM%、load) 📅 2026/7/9 18:10:41 Linux /proc 文件系统实战手动计算 top 命令 3 大核心指标CPU%、MEM%、load在 Linux 系统监控领域top命令无疑是每个运维工程师和开发者的必备工具。它能实时展示系统的 CPU 使用率、内存占用和负载平均值等关键指标。但你是否曾好奇这些数据是如何计算出来的本文将带你深入/proc文件系统通过 Python 脚本手动计算这些指标彻底理解其背后的原理。1. 理解 /proc 文件系统/proc是 Linux 提供的一个虚拟文件系统它不占用磁盘空间而是内核运行时信息的动态映射。通过读取/proc下的各种文件我们可以获取系统运行的几乎所有细节信息。关键文件说明/proc/stat系统 CPU 活动的统计信息/proc/meminfo内存使用情况的详细信息/proc/loadavg系统负载平均值/proc/[pid]/stat特定进程的统计信息提示/proc中的文件看起来是普通文本文件但实际上每次读取时内核都会动态生成内容。2. 计算 CPU 使用率CPU 使用率的计算需要理解几个关键概念用户态时间usertimeCPU 执行用户空间程序的时间内核态时间systemtimeCPU 执行内核代码的时间空闲时间idletimeCPU 空闲的时间I/O 等待时间iowaitCPU 等待 I/O 完成的时间2.1 计算原理CPU 使用率是通过比较两个时间点的 CPU 时间计数器差值来计算的def calculate_cpu_usage(): with open(/proc/stat) as f: lines f.readlines() # 第一行是总体CPU统计 cpu_line lines[0].strip().split() # 提取各时间片计数器 user int(cpu_line[1]) nice int(cpu_line[2]) system int(cpu_line[3]) idle int(cpu_line[4]) iowait int(cpu_line[5]) irq int(cpu_line[6]) softirq int(cpu_line[7]) # 计算总CPU时间 total user nice system idle iowait irq softirq # 计算非空闲时间 non_idle user nice system irq softirq return (non_idle / total) * 1002.2 进程级 CPU 使用率对于特定进程我们需要从/proc/[pid]/stat获取信息def get_process_cpu_usage(pid): with open(f/proc/{pid}/stat) as f: stat f.read().split() # 进程在用户态运行的时间时钟滴答数 utime int(stat[13]) # 进程在内核态运行的时间 stime int(stat[14]) # 进程开始时间时钟滴答数 starttime int(stat[21]) # 获取系统启动以来的时钟滴答数 with open(/proc/uptime) as f: uptime_seconds float(f.read().split()[0]) # 获取系统时钟频率每秒滴答数 hz os.sysconf(os.sysconf_names[SC_CLK_TCK]) # 计算进程总CPU时间 total_time utime stime # 计算进程运行时间 seconds uptime_seconds - (starttime / hz) # 计算CPU使用率百分比 cpu_usage 100 * (total_time / hz) / seconds return cpu_usage3. 计算内存使用率内存使用率的计算涉及多个指标理解它们的关系至关重要指标说明来源文件MemTotal总物理内存/proc/meminfoMemFree空闲内存/proc/meminfoBuffers缓冲区使用的内存/proc/meminfoCached页面缓存使用的内存/proc/meminfoSReclaimable可回收的Slab内存/proc/meminfo3.1 系统内存使用率def calculate_memory_usage(): meminfo {} with open(/proc/meminfo) as f: for line in f: key, value line.split(:) meminfo[key] int(value.split()[0]) * 1024 # 转换为字节 total meminfo[MemTotal] free meminfo[MemFree] buffers meminfo[Buffers] cached meminfo[Cached] sreclaimable meminfo[SReclaimable] # 计算已用内存与free命令一致的方法 used total - free - buffers - cached - sreclaimable return (used / total) * 1003.2 进程内存使用率def get_process_memory_usage(pid): with open(f/proc/{pid}/status) as f: for line in f: if line.startswith(VmRSS): rss int(line.split()[1]) * 1024 # 转换为字节 break with open(/proc/meminfo) as f: total int(f.readline().split()[1]) * 1024 return (rss / total) * 1004. 计算系统负载Load Average系统负载表示单位时间内处于运行状态或不可中断状态的进程平均数。Linux 提供了 1分钟、5分钟和15分钟三个时间段的平均值。4.1 负载计算原理负载计算采用指数加权移动平均法公式为load(t) load(t-1) * e^(-5/60) n * (1 - e^(-5/60))其中 n 是当前活跃进程数。4.2 实现代码def get_load_average(): with open(/proc/loadavg) as f: load1, load5, load15 map(float, f.read().split()[:3]) return { 1min: load1, 5min: load5, 15min: load15 }5. 完整实现与验证下面是一个完整的 Python 脚本实现了上述所有功能并能与top命令的输出进行对比验证#!/usr/bin/env python3 import os import time class SystemMonitor: staticmethod def get_cpu_cores(): 获取CPU核心数 with open(/proc/cpuinfo) as f: return len([line for line in f if line.startswith(processor)]) def get_cpu_usage(self): 获取系统CPU使用率 with open(/proc/stat) as f: lines f.readlines() cpu_line lines[0].strip().split() user int(cpu_line[1]) nice int(cpu_line[2]) system int(cpu_line[3]) idle int(cpu_line[4]) iowait int(cpu_line[5]) irq int(cpu_line[6]) softirq int(cpu_line[7]) total user nice system idle iowait irq softirq non_idle user nice system irq softirq return (non_idle / total) * 100 if total 0 else 0 def get_memory_usage(self): 获取系统内存使用率 meminfo {} with open(/proc/meminfo) as f: for line in f: key, value line.split(:) meminfo[key] int(value.split()[0]) * 1024 total meminfo[MemTotal] free meminfo[MemFree] buffers meminfo[Buffers] cached meminfo[Cached] sreclaimable meminfo[SReclaimable] used total - free - buffers - cached - sreclaimable return (used / total) * 100 if total 0 else 0 def get_load_average(self): 获取系统负载 with open(/proc/loadavg) as f: load1, load5, load15 map(float, f.read().split()[:3]) return { 1min: load1, 5min: load5, 15min: load15 } def get_process_info(self, pid): 获取指定进程的CPU和内存使用情况 try: with open(f/proc/{pid}/stat) as f: stat f.read().split() with open(f/proc/{pid}/status) as f: status {line.split(:)[0]: line.split(:)[1].strip() for line in f if : in line} # 计算CPU使用率 utime int(stat[13]) stime int(stat[14]) starttime int(stat[21]) with open(/proc/uptime) as f: uptime_seconds float(f.read().split()[0]) hz os.sysconf(os.sysconf_names[SC_CLK_TCK]) total_time utime stime seconds uptime_seconds - (starttime / hz) cpu_usage 100 * (total_time / hz) / seconds if seconds 0 else 0 # 计算内存使用率 vm_rss int(status[VmRSS].split()[0]) * 1024 # KB to bytes with open(/proc/meminfo) as f: total_mem int(f.readline().split()[1]) * 1024 mem_usage (vm_rss / total_mem) * 100 if total_mem 0 else 0 return { pid: pid, name: stat[1].strip(()), cpu: cpu_usage, mem: mem_usage } except FileNotFoundError: return None if __name__ __main__: monitor SystemMonitor() print( 系统监控 ) print(fCPU 使用率: {monitor.get_cpu_usage():.2f}%) print(f内存使用率: {monitor.get_memory_usage():.2f}%) load monitor.get_load_average() print(f系统负载: 1分钟{load[1min]}, 5分钟{load[5min]}, 15分钟{load[15min]}) # 获取当前shell进程的信息作为示例 shell_pid os.getppid() process_info monitor.get_process_info(shell_pid) if process_info: print(f\n 进程 {shell_pid} ({process_info[name]}) ) print(fCPU 使用率: {process_info[cpu]:.2f}%) print(f内存使用率: {process_info[mem]:.2f}%)6. 实际应用与优化建议理解这些底层指标的计算方法后我们可以开发更精细化的监控系统或者针对特定场景进行优化性能调优当发现 CPU 使用率高时可以区分是用户态还是内核态高分别采取不同优化策略容量规划通过长期监控内存使用趋势合理规划服务器资源异常检测当负载平均值持续高于 CPU 核心数的 2-3 倍时可能表示系统过载容器监控在容器环境中这些指标对于资源限制和调度尤为重要注意在实际生产环境中建议使用经过充分测试的监控工具如 Prometheus、Datadog 等它们已经实现了这些指标的精确计算和长期存储。