/proc 详解 —— 内核把自己"导出成文件"的窗口
这篇文档是做什么的
本仓库几乎每一篇工具文档都在读
/proc里的某个文件:top/pidstat 读/proc/<pid>/stat、free 读/proc/meminfo、mmap篇看/proc/<pid>/maps、core_pattern在/proc/sys/...。/proc是这些工具共同的数据源。本篇把它当成一个独立主题讲透:/proc到底是什么(不是磁盘上的文件!)、目录怎么组织(进程级 vs 系统级)、每类文件对应内核里的什么、怎么用它排查、以及/proc/sys(sysctl) 怎么改内核行为。
可以回答什么问题
| 问题 | 答案在哪 |
|---|---|
/proc 为什么文件大小是 0 却有内容? | §零、§5.4——不是磁盘文件,是内核现场生成的文本 |
| top/free/iostat 的数据哪来的? | §三——/proc/stat/meminfo/diskstats 文件 |
| 一个进程打开了哪些文件?内存在哪里? | §二——/proc/<pid>/fd、/proc/<pid>/maps |
cat /proc/xxx 时内核到底做了什么? | §五——VFS → procfs → seq_file → 现场读内核数据 |
/proc/sys 和 sysctl 是什么关系? | §四——同一套东西,路径分隔符不同 |
/proc 和 /sys 的分工是什么? | §七——进程/内核信息 vs 设备/硬件拓扑 |
容器里的 /proc 可信任吗? | §六——cpuinfo/meminfo 常显示宿主机值,看 cgroup 更准确 |
相关:进程级文件对应的内核结构见 task-struct;地址空间
maps见 mmap 与 memory-layout;各工具怎么用这些文件见 top/pidstat/vmstat/free。
零、一句话认知:/proc 是一个"虚拟文件系统",文件内容是内核实时生成的
/proc 里的东西不在任何磁盘上。它是一种 虚拟文件系统(procfs):你 cat 一个文件的瞬间,内核临时把当前状态格式化成文本返回给你。文件大小几乎都是 0(还没读时没有内容),但一读就有实时数据。

核心记忆:
/proc是内核状态的只读(大部分)文本视图,读它 = 让内核现场生成一份快照。所以/proc里的文件"大小 0 却有内容"、"每次读都可能变"——它们是接口,不是数据文件。/proc/sys下少数文件可写,写入 = 调节内核参数。
一、三大类:按 PID 的进程目录 / 系统全局 / 可调参数
ls /proc 看到的东西分三类:

/proc/self:一个特殊符号链接,永远指向读它的那个进程自己的/proc/<pid>——脚本里不知道自己 PID 时很有用(cat /proc/self/status)。/proc/thread-self:指向当前线程的/proc/<pid>/task/<tid>。
二、进程级:/proc/<pid>/ —— 一个进程的全部家当
这是 task-struct §四的展开。每个 /proc/<pid>/ 子项对应内核里那个进程的某个资源对象:
| 路径 | 内容 | 对应内核结构 | 谁在用 |
|---|---|---|---|
status | 人类可读汇总:Name/State/Tgid/Pid/PPid/Threads/VmRSS/Uid/CapEff… | task_struct 本体 | ps、排查通用 |
| stat | 单行原始字段:state、utime/stime、min_flt/maj_flt、priority、starttime、第39字段=上次所在核 | task_struct | top/pidstat |
statm / smaps | 内存用量(页数)/ 每段详细 RSS/PSS/脏页 | mm_struct | 内存分析 |
maps | VMA 列表:每段虚拟地址/权限/后备文件 | mm_struct 的 VMA | mmap/memory-layout |
fd/ | 打开的每个 fd → 指向的文件/socket | files_struct | lsof |
task/ | 线程组里每个线程一个 <tid>/ 子目录 | 一组 task_struct | top -H/ps -L |
cwd/root/exe | 当前目录/根目录/可执行文件(符号链接) | fs_struct / mm | 排查 |
cmdline/environ | 启动命令行 / 环境变量 | — | 看进程身份 |
sched/schedstat | vruntime、被调度次数、等待时间 | 调度实体 | scheduling |
limits | 资源上限(rlimit) | signal_struct | 排查 ulimit |
ns/ | 所属各命名空间 | nsproxy | 容器排查 |
numa_maps | 各内存段落在哪个 NUMA 节点 | mm + 内存策略 | numa |
coredump_filter/dumpable | core dump 行为控制 | — | core-dump |
cat /proc/$$/status # $$ = 当前 shell 的 PID
cat /proc/self/maps # 读它的进程自己的地址空间布局
ls -l /proc/1234/fd # 进程 1234 打开的所有 fd
cat /proc/1234/task/*/stat # 该进程每个线程的调度状态
/proc/<pid>/展开的每一项,都是 task-struct 里那张"资源对象总表"的文件化投影。要理解字段背后的结构,回那篇看。
三、系统级:整机状态与统计
不带 PID 的顶层文件,反映全系统状态。挑最常用的:
| 文件 | 内容 | 相关工具 |
|---|---|---|
/proc/meminfo | 内存总量/可用/cache/buffers/swap/脏页/HugePage… | free |
/proc/vmstat | 内存管理细粒度计数:换页、缺页、回收… | vmstat |
/proc/stat | 全系统 CPU 时间(user/nice/system/idle/iowait/irq)、上下文切换总数、启动后中断数 | top/mpstat/vmstat |
/proc/loadavg | 1/5/15 分钟平均负载 + 运行/总任务数 | uptime |
/proc/cpuinfo | 每个逻辑 CPU 的型号/主频/缓存大小/标志位 | 查硬件 |
/proc/interrupts | 每个中断号在每个 CPU 上的计数 | 中断亲和性(thread-affinity) |
/proc/softirqs | 软中断计数(NET_RX 等) | 网络排查 |
/proc/diskstats | 每块设备的 IO 计数(次数/扇区/耗时) | iostat |
/proc/net/* | tcp/udp/dev 等网络栈状态 | ss |
/proc/mounts//proc/filesystems | 挂载表 / 支持的文件系统 | 排查挂载 |
/proc/uptime / /proc/version | 开机时长 / 内核版本 | — |
要点:top/free/vmstat/iostat 这些工具本身不神秘——它们就是定期读上面这些文件、做差值、算速率、格式化显示。看懂
/proc/stat,就看懂了 CPU 利用率是怎么算出来的(两次采样求各态时间增量占比)。
四、/proc/sys —— 可写的内核旋钮(sysctl)
/proc/sys/ 下的文件可以写,写入即刻改变内核行为。它和 sysctl 命令是同一套东西(路径 /proc/sys/a/b/c ↔ sysctl a.b.c):
# 读
cat /proc/sys/vm/swappiness # = sysctl vm.swappiness
# 临时改(重启失效),两种等价写法
echo 10 > /proc/sys/vm/swappiness
sysctl -w vm.swappiness=10
# 永久改:写进 /etc/sysctl.conf 或 /etc/sysctl.d/*.conf,然后 sysctl -p本仓库出现过的几个 /proc/sys 旋钮:
| 路径 | 作用 | 出处 |
|---|---|---|
/proc/sys/kernel/core_pattern | core dump 文件名/管道模板 | core-dump |
/proc/sys/kernel/randomize_va_space | ASLR 开关(0/1/2) | memory-layout |
/proc/sys/kernel/numa_balancing | 自动 NUMA 均衡 | numa |
/proc/sys/vm/overcommit_memory | 内存超额分配策略 | free |
/proc/sys/vm/drop_caches | 手动释放 page cache(测试用) | 内存实验 |
/proc/sys/vm/swappiness | 倾向换页的程度 | 内存调优 |
注意:直接
echo >只是临时改动,重启丢失;要持久化用/etc/sysctl.d/。写这些旋钮多数需要 root,且改错(如overcommit/core_pattern)会影响全系统稳定性——生产环境务必清楚含义再改。完整的配置入口地图(sysctl / /sys / 启动参数怎么选)见 kernel-tuning。
五、原理:cat /proc/xxx 时内核到底做了什么
前面说"读它=内核现场生成快照"是结论,这一节讲机制:procfs 凭什么能让一个"文件"在被读时才产生内容。
5.1 procfs 是一个挂载的文件系统,接进了 VFS
Linux 一切文件操作都走 VFS(虚拟文件系统层)——它定义了 open/read/write 等操作的抽象接口,底下可以挂各种真实实现(ext4、xfs、tmpfs……)。procfs 就是其中一种文件系统实现,开机时被挂载到 /proc:
mount | grep proc # proc on /proc type proc (rw,...) ← 一个 type=proc 的文件系统- 它注册了一个
file_system_type,挂载后/proc这棵目录树的每个节点(inode)都由 procfs 提供。 - 关键在于:procfs 的 inode 绑定的
file_operations里,.read指向的不是"读磁盘块",而是内核自己的一个函数。于是用户态read()经 VFS 分发,最终调到那个内核函数——内容是函数当场算出来的,不是从存储里取的。

这就是"虚拟"的技术含义:procfs 复用了 VFS 的文件抽象(所以你能
open/read/cat),但把"读数据"这个动作替换成"调用一个内核函数生成数据"。文件只是接口外壳,背后是活的内核状态。
5.2 seq_file:procfs 文件内容的标准生成框架
早期 procfs 的 read 处理器要自己管缓冲区、偏移、边界,很容易出 bug(尤其内容跨多次 read、或长度超过一页时)。现在绝大多数 /proc 文件用 seq_file(sequence file) 框架生成内容,它把"输出一段文本"抽象成遍历一个序列:
- 驱动方(某个 /proc 文件的实现)提供四个回调:
start()/next()/stop()/show()。 - 内核把它们当成迭代器:
start定位到第一个元素 →show把当前元素格式化成文本(用seq_printf往缓冲里写)→next移到下一个 → 直到stop。 seq_file自动处理:缓冲区扩容、用户多次read的偏移续接、lseek——实现者只管"怎么把一个元素变成一行文本"。
以 /proc/<pid>/status 为例:它的 show() 就是当场读那个进程的 task_struct 字段(state、pid、VmRSS……),用 seq_printf 拼成 Name:\t...\nState:\t...\n 这样的文本。你每 cat 一次,show() 就重跑一次,读的是此刻的 task_struct —— 这就是"值是活的"的根源。

5.3 目录树怎么建:proc_dir_entry 与动态生成
- 静态节点:系统级文件(
/proc/meminfo、/proc/stat等)在内核初始化/模块加载时,通过proc_create()注册一个proc_dir_entry(procfs 的目录项),绑定各自的file_operations/seq_operations。内核子系统各自登记自己的那几个文件。 - 动态节点:
/proc/<pid>/这类不是预先建好的——系统里进程时刻在增减,不可能为每个进程静态建目录。procfs 在你查找/遍历/proc时动态生成:ls /proc时,procfs 遍历内核进程链表,为每个存在的 task 现场"变出"一个<pid>目录;open /proc/1234/status时,先按 1234 找到对应task_struct,再生成该文件。进程没了,对应目录下次就查不到了。 - 这也解释了 §零说的"文件大小是 0":
proc_dir_entry没有真实长度,stat()拿不到大小,只有真去read触发show()才有内容。
5.4 由原理反推的几个现象
| 现象 | 原理解释 |
|---|---|
| 文件大小 0 却有内容 | 没有后备存储,大小无意义;内容是 read 时 show() 现算的 |
| 连读两次值不同 | 每次 read 都重新读当前内核状态,不缓存 |
/proc/<pid> 进程退出就消失 | 目录是查找时按 task_struct 动态生成的,进程没了就生成不出来 |
| 几乎没有磁盘 IO | procfs 的 .read 是内核函数,不碰块设备 |
/proc/sys 可写 | 那些节点的 .write 回调绑到"设置某内核变量"的函数上,写入即赋值 |
| 容器里 meminfo 是宿主机的 | procfs 的 show() 默认读宿主机全局变量,不感知 cgroup(除非 lxcfs 拦截) |
一句话讲原理:procfs 是一个挂在 VFS 下的文件系统实现,它把文件的
read/write操作接管成"调用内核函数现场生成/接收数据"(大多用seq_file框架遍历内核结构、seq_printf输出);进程目录/proc/<pid>则在被访问时按task_struct动态生成。所以它有文件的外壳(能 open/read/cat)、却无文件的实体(不落盘、大小 0、值实时变)。
六、怎么读这些文件:注意事项
- 别用文件大小判断内容:
ls -l /proc/meminfo显示 0 字节,但 cat 有满屏内容——大小是假的,必须真去read。 - **值是"活的" **:连续读两次
/proc/stat会不同。利用率/速率类指标都要"采两次样求差值"——这正是 top/vmstat 每隔 N 秒刷新的原因。 - stat 字段靠位置:
/proc/<pid>/stat是空格分隔的一长行,靠字段序号取值(如第 14/15 是 utime/stime、第 39 是所在 CPU)。字段含义查man 5 proc。 man 5 proc是权威手册:每个文件的精确格式都在这里,拿不准就查它。- 权限:别的用户的
/proc/<pid>/里敏感项(environ、maps)通常只有属主/root 能读。 - **容器里 /proc 可能是"部分虚假的" **:容器内
/proc/cpuinfo/meminfo常显示宿主机的值(除非用 lxcfs 之类矫正),排查容器资源要看 cgroup 而非 /proc。
七、和 /sys、/proc 的分工(别混)
/proc:历史上先有,混装"进程信息"+"内核杂项"+"可调参数(/proc/sys)"。/sys(sysfs):后来引入,专门以更规整的层级导出设备与内核对象模型(块设备、CPU 拓扑、cgroup v1 的部分接口等)。- 经验:进程/传统内核信息 →
/proc;设备与硬件拓扑 →/sys。两者都是虚拟文件系统,读法一样。
八、和本仓库其他文档的关系
- 进程级文件的结构来源:task-struct(status/maps/fd/task 对应哪个内核对象)、scheduling(sched/schedstat)。
- 地址空间:mmap、memory-layout(maps/smaps/numa_maps)。
- 系统级文件的消费者:top/pidstat/mpstat/vmstat、scheduling-observation、free、iostat、iotop、ss、../network/lsof、rdma、numactl、numastat、sar、perf、strace。
- /proc/sys 旋钮:core-dump(core_pattern)、memory-layout(ASLR)、numa、thread-affinity(interrupts/中断亲和);配置入口全景见 kernel-tuning。
- 原理相关:compile-link-load(open/read 走系统调用)、syscall(read 陷入内核)。
九、一句话总结
/proc是一个不落盘的虚拟文件系统(procfs):你每次 read 它,内核就现场把task_struct/mm_struct/全局计数器等状态格式化成文本返回——所以文件大小是 0、内容却是活的。它分三类:/proc/<pid>/(每进程一个目录,是 task_struct 及其资源对象的文件化投影)、系统级全局文件(meminfo/stat/cpuinfo/diskstats/net… 是 top/free/vmstat/iostat 的共同数据源,利用率靠采两次样求差值)、以及可写的/proc/sys(sysctl 旋钮,调节内核行为但改错影响全系统)。设备与硬件拓扑则归/sys。看懂 /proc,就看懂了本仓库几乎所有性能工具的数据从哪来。
FAQ
Q: /proc 里的文件为什么大小是 0 却有内容? A: /proc 是虚拟文件系统,文件不落盘。cat 的瞬间内核现场把状态格式化成文本返回,所以 ls -l 显示 0 字节、一读就有实时数据。
Q: top/free/vmstat 的数据是从哪来的? A: 它们读的都是 /proc/stat、/proc/meminfo、/proc/diskstats 这些系统级文件;利用率类指标靠"采两次样求差值"计算。
Q: 为什么连续读两次 /proc/stat 结果不一样? A: /proc 的值是"活的",每次 read 都重新生成当前计数。利用率/速率必须采两次样求差值,这正是 top/vmstat 定期刷新的原因。
Q: 容器里的 /proc 可信任吗? A: 不完全。容器内 /proc/cpuinfo、/proc/meminfo 常显示宿主机值(除非用 lxcfs 矫正),排查容器资源要看 cgroup 而非 /proc。
Q: /proc 和 /sys 有什么区别? A: /proc 装进程信息+内核杂项+可调参数;/sys(sysfs) 专门以规整层级导出设备与内核对象模型。进程/传统内核信息归 /proc,设备/硬件拓扑归 /sys。
Q: /proc/sys 和 sysctl 是什么关系? A: 同一套东西。echo 1 > /proc/sys/vm/swappiness 与 sysctl vm.swappiness=1 等价,只是路径分隔符不同。