/proc/self/status讲解

本文探讨了Linux进程中Name、State、SleepAVG等关键参数的含义,重点解读VmRSS和VmSize的区别,以及它们在内存使用情况中的实际意义,结合实例解析内存管理和任务状态分析技巧。
部署运行你感兴趣的模型镜像

[root@localhost ~]# cat /proc/self/status
Name: cat
State: R (running)
SleepAVG: 88%
Tgid: 5783
Pid: 5783
PPid: 5742
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 256
Groups: 0 1 2 3 4 6 10
VmSize: 6588 kB
VmLck: 0 kB
VmRSS: 400 kB
VmData: 144 kB
VmStk: 2040 kB
VmExe: 14 kB
VmLib: 1250 kB
StaBrk: 0804e000 kB
Brk: 088df000 kB
StaStk: bfe03270 kB
ExecLim: 0804c000
Threads: 1
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 00000000fffffeff
CapEff: 00000000fffffeff

输出解释
参数 解释
Name 应用程序或命令的名字
State 任务的状态,运行/睡眠/僵死/
SleepAVG 任务的平均等待时间(以nanosecond为单位),交互式任务因为休眠次数多、时间长,它们的 sleep_avg
也会相应地更大一些,所以计算出来的优先级也会相应高一些。
Tgid 线程组号
Pid 任务ID
Ppid 父进程ID
TracerPid 接收跟踪该进程信息的进程的ID号
Uid Uid euid suid fsuid
Gid Gid egid sgid fsgid
FDSize 文件描述符的最大个数,file->fds
Groups
VmSize(KB) 任务虚拟地址空间的大小
(total_vm-reserved_vm),其中total_vm为进程的地址空间的大小,reserved_vm:进程在预留或特殊的内存间的物理页
VmLck(KB) 任务已经锁住的物理内存的大小。锁住的物理内存不能交换到硬盘 (locked_vm)
VmRSS(KB) 应用程序正在使用的物理内存的大小,就是用ps命令的参数rss的值 (rss)
VmData(KB) 程序数据段的大小(所占虚拟内存的大小),存放初始化了的数据;
(total_vm-shared_vm-stack_vm)
VmStk(KB) 任务在用户态的栈的大小 (stack_vm)
VmExe(KB) 程序所拥有的可执行虚拟内存的大小,代码段,不包括任务使用的库 (end_code-start_code)
VmLib(KB) 被映像到任务的虚拟内存空间的库的大小 (exec_lib)
VmPTE 该进程的所有页表的大小,单位:kb
Threads 共享使用该信号描述符的任务的个数,在POSIX多线程序应用程序中,线程组中的所有线程使用同一个信号描述符。
SigQ 待处理信号的个数
SigPnd 屏蔽位,存储了该线程的待处理信号
ShdPnd 屏蔽位,存储了该线程组的待处理信号
SigBlk 存放被阻塞的信号
SigIgn 存放被忽略的信号
SigCgt 存放被俘获到的信号
CapInh Inheritable,能被当前进程执行的程序的继承的能力
CapPrm
Permitted,进程能够使用的能力,可以包含CapEff中没有的能力,这些能力是被进程自己临时放弃的,CapEff是CapPrm的一个子集,进程放弃没有必要的能力有利于提高安全性
CapEff Effective,进程的有效能力

范例 1
可以看出该应用程序的正文段(1KB)很小,说明代码很少,是依靠库(1251KB)来执行。栈(138KB)适中,说明 没有太多许多嵌套函数或特别多的临时变量。VmLck为0说明进程没有锁住任何页。VmRSS表示当前进程使用的物理内存为2956KB。当进程开始使用 已经申请的但还没有用的内存时,VmRSS的值开始增大,但是VmSize保持不变。
[root@localhost 1]# cat /proc/4668/status
Name: gam_server
State: S (sleeping)
SleepAVG: 88%
Tgid: 31999
Pid: 31999
PPid: 1
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 256
Groups: 0 1 2 3 4 6 10
VmSize: 2136 kB
VmLck: 0 kB
VmRSS: 920 kB
VmData: 148 kB
VmStk: 88 kB
VmExe: 44 kB
VmLib: 1820 kB
VmPTE: 20 kB
Threads: 1
SigQ: 1/2047
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000001006
SigCgt: 0000000210000800
CapInh: 0000000000000000
CapPrm: 00000000fffffeff
CapEff: 00000000fffffeff
[root@localhost 31999]#4 /proc//statm
包含了所有CPU活跃的信息,该文件中的所有值都是从系统启动开始累计到当前时刻。

[root@localhost ~]# cat /proc/self/statm
654 57 44 0 0 334 0

以下是我自己的理解:

从上面可以看出VmRSS才是我们最关心的内存大小,即

正在使用的物理内存的大小;

而VmSize是进程所拥有的虚拟空间的大小;

“当进程开始使用 已经申请的但还没有用的内存时,

VmRSS的值开始增大,但是VmSize保持不变。”

我们之所以看到许多内存的值的大小超过了内存的总的大小

是因为这里显示的都是虚拟内存的大小,而不是实际的占用的大小;

这是其它的地方的解释

From cat /proc/4743/statm
611450 185001 883 18 0 593431 0

  1. size :- total program size (611450 X 4096/1024 = 2445800kB = 2388M)
  2. resident :- resident set size (185001 X 4096/1024 = 740004kB = 722M)
  3. share :- shared pages (883 X 4096 = 3532)
  4. trs :- text (code) (18 X 4096/1024 = 72kB = VmExe )
  5. drs :- data/stack
  6. lrs :- library (593431 X 4096/1024 = 2373724kB = VmData +VmStk)
  7. dt :- dirty pages

从这里可以看出第一项是进程的可执行的大小,X4就等于VmSize

而第二项的值X4就等于VmRSS

#补充 by wylhistory:

对于信号那几个段:

SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000001006
SigCgt: 0000000210000800

其中前32位分别表示普通的信号,比如:

SigBlk: 0000000000002000
这里表示SIGALRM已经被阻塞了,

因为SIGALRM的值就是14;

而里面的Siglgn:1006就表示:

类型为2,3,13的信号被忽略了,

分别是:SIGINT,SIGQUIT,SIGPIPE,

记得从1开始而不是0,因为信号没有类型为0的信号;

后32位的一般不用管为实时信号;

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think>嗯,用户这次想深入了解Linux守护进程的工作原理和具体实现方式。从对话历史看,之前用户已经通过站内引用获取了部分基础概念,现在需要更系统的技术解析。用户可能是个刚接触Linux系统编程的开发者,或者在搭建需要后台服务的应用,daemon的实现细节对他很关键。注意到用户引用的资料中特别提到“两次fork”和“脱离终端”两个技术点,这应该是核心难点。用户可能在实际开发中遇到了daemon进程异常退出或被终端信号干扰的问题,所以需要理解背后的机制。另外用户没有提到具体编程语言,但根据历史引用中出现的APUE(《AdvancedProgrammingintheUNIXEnvironment》),大概率是用C语言实现。从专业角度,需要分三层讲清楚:首先是原理层,必须解释daemon的四个核心特征:生命周期独立、无控制终端、会话首进程、工作目录隔离。引用[3]提到的syslog日志机制也值得展开,这是daemon唯一的输出通道。然后是代码实现层,两次fork的每个步骤都要说明白:第一次fork是为了脱离shell成为后台进程,setsid创建新会话切断终端关联,第二次fork避免意外获取终端。这里需要强调文件描述符处理和umask重置的实操细节。最后补充些工程经验,比如用systemd管理daemon的现代方式,毕竟用户可能在生产环境部署。检测手段也很实用,用户肯定需要验证自己写的daemon是否符合规范。不过要控制深度,用户没提及时钟守护进程或inetd等高级主题,暂时不需要展开。但安全考虑建议加上日志轮换和权限最小化的提示,避免用户写出有安全隐患的daemon。</think> 好的,我们来系统梳理一下Linux守护进程(Daemon)的原理及其关键实现步骤。核心目标是创建一个**长期运行、独立于终端、不受用户登录/注销影响**的后台服务进程。 **一、守护进程的核心原理** 1. **生命周期长**: * 通常在系统启动时由init(现代Linux多为systemd)启动,持续运行直至系统关闭。 * 用于提供系统级或网络服务(如Web服务器`httpd`、数据库`mysqld`、日志服务`syslogd`、计划任务`crond`等)。 2. **脱离控制终端 (Terminal)** [^1][^3]: * **为什么需要脱离?**: * 避免干扰用户:守护进程的输出不应混杂在用户的终端会话中。用户注销后再次登录同一终端时,不应看到先前守护进程的输出或错误。 * 避免信号干扰:终端产生的信号(如`Ctrl+C`发送的`SIGINT`,终端断开发送的`SIGHUP`)不应意外终止守护进程。 * **如何体现?**:守护进程的`tty`字段显示为`?`。 3. **自成会话 (Session) 和进程组 (Process Group)**: * 守护进程通常是自己所在会话的唯一进程,且是该会话的首进程。 * 这确保了它与任何登录会话和终端彻底解耦。 4. **后台运行**: * 没有对终端(标准输入/输出/错误)的依赖,通常在后台默默运行。 5. **工作目录更改**: * 为避免占用文件系统(如挂载点),通常将工作目录切换到根目录`/`。 6. **文件权限掩码重设 (`umask`)**: * 清除继承来的文件模式创建屏蔽字(`umask`),通常设为`0`。这确保了守护进程创建的文件和目录有预期的权限(如日志文件),不受父进程`umask`的限制。 7. **处理文件描述符**: * 关闭所有从父进程继承来的、不再需要的文件描述符(特别是标准输入`stdin`、标准输出`stdout`、标准错误`stderr`)。 * 为了避免这些描述符指向终端或已关闭导致错误,通常将它们重定向到`/dev/null`或日志文件。 8. **可靠的日志输出**: * 由于脱离了终端,守护进程不能直接使用`printf`。需要通过`syslog`函数族将日志消息发送给`syslogd`或`rsyslogd`守护进程统一管理[^3]。这是守护进程报告状态、错误和事件的**标准方式**。 **二、守护进程实现的关键步骤** 创建一个标准守护进程通常遵循以下步骤(通常在程序启动早期执行,如`main()`函数初始化阶段): 1. **`fork()` 第一次并退出父进程**: ```c pid_t pid = fork(); if (pid < 0) { // 创建子进程失败 exit(1); // 或处理错误 } else if (pid > 0) { // 父进程 exit(0); // 父进程优雅退出,子进程继续运行成为孤儿进程,被init/sytemd接管 } ``` * **目的**:使子进程在后台运行(成为init/systemd的“养子”),并脱离原始shell进程的控制。原始shell(父进程)认为命令已执行完毕并退出。 2. **调用 `setsid()` 创建新会话**: ```c if (setsid() < 0) { // 成为新会话的首进程和新进程组的组长进程 exit(1); // 失败处理 } ``` * **核心作用**:使进程摆脱其与控制终端的关联(如果有的话),并成为新会话的首进程(Session Leader)和新进程组的组长进程(Process Group Leader)。这**彻底切断了与原终端的所有联系**[^1][^3]。 3. **`fork()` 第二次并退出父进程**: ```c pid = fork(); if (pid < 0) { exit(1); } else if (pid > 0) { // 父进程(Session Leader) exit(0); // 父进程退出,子进程(非Session Leader)继续运行 } ``` * **目的**:确保**新创建的守护进程绝不是新会话的首进程**。这彻底阻止了它将来有重新获得控制终端的可能性(在Linux/Unix中,只有会话首进程才能申请打开一个控制终端)。 4. **可选但强烈推荐:更改工作目录 (`chdir`) 和 设置文件创建掩码 (`umask`)**: ```c chdir("/"); // 避免占用文件系统挂载点 umask(0); // 清除继承的umask,以便按需设置文件权限 (如 0666) ``` 5. **关闭/重定向标准文件描述符**: ```c close(STDIN_FILENO); // 关闭标准输入 (文件描述符0) close(STDOUT_FILENO); // 关闭标准输出 (文件描述符1) close(STDERR_FILENO); // 关闭标准错误 (文件描述符2) // 或者更健壮的方式,重定向到/dev/null,避免后续操作(如第三方库)使用这些描述符出错: int fd0 = open("/dev/null", O_RDWR); // 对应stdin int fd1 = dup(fd0); // 复制fd0到stdout (1) int fd2 = dup(fd0); // 复制fd0到stderr (2) if (fd0 != STDIN_FILENO || fd1 != STDOUT_FILENO || fd2 != STDERR_FILENO) { // 处理错误 } ``` * 关闭继承的所有其他不必要的文件描述符(通过`getrlimit`或遍历`/proc/self/fd`并关闭大于特定值的描述符)。 6. **设置 `syslog` (或其他可靠日志机制)**: ```c openlog("mydaemon", LOG_PID | LOG_CONS, LOG_DAEMON); // 打开系统日志连接 syslog(LOG_NOTICE, "My Daemon is starting up!"); // 记录日志消息 // ... (在代码中使用syslog记录重要信息) ``` * **关键**:这是守护进程报告状态、错误和事件的**主要途径**。 7. **守护进程主体逻辑**: * 在此处实现守护进程的核心功能(例如,监听网络端口、轮询任务队列、处理定时事件等)。通常是一个永不退出的循环(或通过信号控制退出)。 8. **处理信号**: * 为`SIGTERM`(默认终止信号)、`SIGHUP`(常用于配置重载)等关键信号注册处理函数。`SIGKILL`和`SIGSTOP`不能被捕获。 * 在终止信号处理函数中执行清理工作(关闭文件/网络连接、释放资源)并向`syslog`记录结束信息。 **三、实践与检查** * **使用 `systemd` 管理现代守护进程**:现代Linux发行版使用`systemd`管理守护进程。守护进程应实现`systemd`服务单元文件(`.service`文件)规定的接口(如正确响应`SIGTERM`,可选的套接字/总线激活,状态通知等)以获得更好的生命周期管理、日志集成(`journald`)、依赖管理等优势[^1][^2]。 * **检查守护进程状态**: * `ps -efj | grep '[m]ydaemon'`:查看进程状态,特别是`TTY`应为`?`,`SID`(会话ID)应为其自身`PID`或为其父`PID`(第二次`fork`的情况)。 * `systemctl status mydaemon.service`:如果使用`systemd`管理。 * 查看`/var/log/syslog`、`/var/log/messages`或使用`journalctl -u mydaemon.service`:确认守护进程是否通过`syslog`正确记录日志。 **总结:** Linux守护进程的设计核心在于**隔离与自治**。两次`fork` + `setsid`是创建可靠、独立于终端守护进程的经典模式。关闭/重定向文件描述符、更改工作目录、设置`umask`、使用`syslog`是确保其稳定性和可控性的关键措施。在现代系统上,与`systemd`或类似服务管理器的良好集成对于复杂的生产环境守护进程至关重要[^1][^2][^3]。 --- **
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值