通过 /proc/[pid]/ 查看进程状态
来源:互联网 发布:剑网三怎么在淘宝买金 编辑:程序博客网 时间:2024/05/20 23:30
参考资料
[/proc官方手册] http://man7.org/linux/man-pages/man5/proc.5.html
[解读/proc/$PID/status中各种参数] https://my.oschina.net/aiguozhe/blog/125477
[查看Linux & Android中内存占用方法] http://blog.csdn.net/myarrow/article/details/7703296
[Measuring Memory Usage] http://locklessinc.com/articles/memory_usage/
[Linux下的/proc/[pid]目录下的文件分析] https://github.com/NanXiao/gnu-linux-proc-pid-intro
[Linux中查看进程占用内存的情况] http://hutaow.com/blog/2014/08/28/display-process-memory-in-linux/
/proc/[pid]/ 目录
在这篇文章中 http://man7.org/linux/man-pages/man5/proc.5.html 详细讲解了/proc 目录下各个文件的意义以及系统调用的方法。
当我们查看进程的时候 #ps –e
或#ps
可以列举出当前进程ID以及名称。
ps 命令的使用可以参考:http://man7.org/linux/man-pages/man1/ps.1.html
其中PID为1的固定为init进程,2的为kthreadd进程。前面的几个进程基本上都是固定的。在 /proc
目录下会有与PID一致的目录名,目录里面的信息就包含该进程的所有信息。对 /proc/[pid]/
目录的解释如下:
比如说 PID=1的init进程的信息存放在 /proc/1/ 的目录如下。
/proc/[pid]/status
将 /proc/[pid]/stat
和 /proc/[pid]/statm
的内容以用户可以直观分析的格式打印出来。这里只列举了其中的几个参数的意义:
* Name: Command run by this process.* State: Current state of the process. One of "R (running)","S (sleeping)", "D (disk sleep)", "T (stopped)", "T (tracingstop)", "Z (zombie)", or "X (dead)".* Pid: Thread ID (see gettid(2)).* VmPeak: Peak virtual memory size.* VmSize: Virtual memory size.* VmLck: Locked memory size (see mlock(3)).* VmPin: Pinned memory size (since Linux 3.2). These arepages that can't be moved because something needs todirectly access physical memory.* VmHWM: Peak resident set size ("high water mark").* VmRSS: Resident set size. Note that the value here is thesum of RssAnon, RssFile, and RssShmem.* RssAnon: Size of resident anonymous memory. (since Linux4.5).* RssFile: Size of resident file mappings. (since Linux 4.5).* RssShmem: Size of resident shared memory (includes System Vshared memory, mappings from tmpfs(5), and shared anonymousmappings). (since Linux 4.5).* VmData, VmStk, VmExe: Size of data, stack, and textsegments.* VmLib: Shared library code size.* VmPTE: Page table entries size (since Linux 2.6.10).* VmPMD: Size of second-level page tables (since Linux 4.0).* VmSwap: Swapped-out virtual memory size by anonymous privatepages; shmem swap usage is not included (since Linux2.6.34).* Threads: Number of threads in process containing thisthread.
- VmPeak: 表示进程所占用最大虚拟内存大小
- VmSize: 表示进程当前虚拟内存大小
- VmLck: 表示被锁定的内存大小
- VmHWM: 表示进程所占用物理内存的峰值
- VmRSS: 表示进程当前占用物理内存的大小(与procrank中的RSS)
- VmData: 表示进程数据段的大小
- VmStk: 表示进程堆栈段的大小
- VmExe: 表示进程代码的大小
- VmLib: 表示进程所使用共享库的大小
- VmPTE: 表示进程页表项的大小
如果我们只想要获取其中某几个参数的值,可以使用命令: #cat /proc/1/status | grep -E 'VmSize|VmRSS'
有这么一个需求:要统计各个进程中占用的物理内存的大小,我总不能一条条去执行cat命令吧,于是我们可以写一个应用程序循环读取每个进程的某个状态值。于是就有了下面的 rdstatus 应用程序
cat /proc/[pid]/stat
stat这个文件包含了很多信息,总共有52个参数。
这些内容在内核代码中:<kernel_dir>/fs/proc/array.c
中实现。
rdstatus 应用程序
rdstatus.c 只能用来获取 /proc/[pid]/status
中的内容。通过读取 /proc
目录下的所有文件,然后提取其中[pid]
的目录,获取到 /proc/[pid]/status
的路径,再组合成 cmd
命令传递给system()
执行。
#if 1#include <stdio.h>#include <stdlib.h>#include <time.h>#include <unistd.h>#include <fcntl.h>#include <unistd.h>#include <sys/mman.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/wait.h>#include <errno.h>#include <unistd.h>#include <dirent.h>#define PROC_DIR_PATH "/proc"#define DIR_MAX 256#define DIR_NAME_MAX 40#define CMD_NAME_MAX 200#define RD_BUFFER_MAX 512#if 0 // 介绍目录操作http://songlee24.github.io/2014/09/20/linux-get-directory/在头文件<dirent.h>中定义了两种主要的数据类型。DIR:代表一个目录流的结构。struct __dirstream{ void *__fd; /* 'struct hurd_fd' pointer for descriptor.*/ char *__data; /* Directory block. */ int __entry_data; /* Entry number `__data' corresponds to.*/ char *__ptr; /* Current pointer into the block.*/ int __entry_ptr; /* Entry number `__ptr' corresponds to.*/ size_t __allocation; /* Space allocated for the block.*/ size_t __size; /* Total valid data in the block.*/ __libc_lock_define (, __lock) /* Mutex lock for this structure.*/};typedef struct __dirstream DIR;struct dirent:包含一个文件或目录信息的结构体。struct dirent{ long d_ino; /* inode number 索引节点号 */ off_t d_off; /* offset to this dirent 在目录文件中的偏移 */ unsigned short d_reclen; /* length of this d_name 文件名长 */ unsigned char d_type; /* the type of d_name 文件类型 */ char d_name [NAME_MAX+1]; /* file name 文件名,最长255字符 */}DIR* opendir(const char* dirname);/* 打开一个目录: 成功 - 返回指向DIR类型对象的指针。 失败 - 返回NULL */int closedir(DIR *dirp);/* 关闭目录流: 成功 - 返回0 失败 - 返回-1 */struct dirent *readdir(DIR *dirp);/* 读取目录流: 成功 - 返回指向struct dirent对象的指针。 失败 - 返回NULL(出错或流末尾) */int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);/* 读取目录流:用 dirp 当前位置的目录初始化entry,并让 result 指向 entry。 成功 - 返回0 失败 - 返回error number */void rewinddir(DIR *dirp);/* 重置目录流的位置到开头 */void seekdir(DIR *dirp, long int loc);/* 设置目录流的位置,设置以后readdir()会读取到loc位置的目录。 */long int telldir(DIR *dirp);/* 返回目录流的当前位置 */#endifint translat(char c){ if(c <= '9'&&c >= '0') return 1; else return -1;}// 判断字符串是否是数字int isStringNum(char *str){ int length = strlen(str); int i,n=0; int cnt=0; if(length == 0) return 0; for(i=0; i<length; i++) { cnt += translat(str[i]); } if(cnt == length) return 1; else return -1;}void ShowHelp(void){ printf("show this help:\n"); printf(" -h : show this help\n"); printf(" -a : cat all pid all message\n"); printf(" -c : cycle yes or not, 0 for not, 1 for yes\n"); printf(" -n : process name\n"); printf(" -p : pid number\n"); printf(" -r : pid rang, pid_min ~ pid_max\n"); printf(" -s : cat status, VmSize VmRSS VmPeak etc\n"); printf("\n"); // 命令控制只能采用以下的格式 printf("for example:\n"); printf(" ./rdstatus -h\n"); // flag = 1 printf(" ./rdstatus -c 1 -a\n"); // flag = 2 printf(" ./rdstatus -c 1 -n init -s VmSize\n");// flag = 3 printf(" ./rdstatus -c 1 -p 1 -s VmSize\n"); // flag = 4 printf(" ./rdstatus -c 1 -r 51 77 -s VmSize\n"); // flag = 5 printf("\n"); printf("argument number must 1 & 4 & 7 or more & 8 or more\n");}int GetRdFlag(int l_argc, char **l_argv){ int flag = 1; if(l_argc == 2) flag = 1; else if(l_argc == 4) flag = 2; else if((l_argc >= 7) && (!strcmp(l_argv[3], "-n"))) flag = 3; else if((l_argc >= 7) && (!strcmp(l_argv[3], "-p"))) flag = 4; else if((l_argc >= 8) && (!strcmp(l_argv[3], "-r"))) flag = 5; else flag = 1; return flag;}// 通过 process name 判断与当前 pid 是否匹配int isProcessMatchPid(char *pid, char *name){ char path[CMD_NAME_MAX]; int ret = 0; int fd = 0; char rd_buf[RD_BUFFER_MAX]; //printf("pid = %s, process_name = %s\n", pid, name); sprintf(path, "/proc/%s/status", pid); //printf("path = %s\n", path); fd = open(path, O_RDWR); if(fd < 0) { printf("open %s error\n", path); return -1; } ret = read(fd, rd_buf, 30); //printf("rd_buf = %s\n", rd_buf); if(strstr(rd_buf, name) != NULL){ //printf("Match process name ok\n"); close(fd); return 1; } else { //printf("Match process name failure\n"); close(fd); return -1; }}void SetCmd(int l_argc, char **l_argv, char *path, char *cmd, char *name){ int j = 0; strcpy(path, PROC_DIR_PATH); // 调用 strcpy() 可重新定位到 status_path 的开头处 strcat(path, "/"); strcat(path, name); strcat(path, "/"); strcat(path, "status"); // 只支持读取 /proc/[pid]/status 的内容 // 确定执行的命令 strcpy(cmd, "cat "); strcat(cmd, path); strcat(cmd, "| grep -E 'Name"); // 固定显示 Name 字段 strcat(cmd, "|"); for(j=6; j<l_argc; j++) { strcat(cmd, l_argv[j]); // 获取 -s 之后的内容 if(j != (l_argc-1)) // 最后不添加 '|' strcat(cmd, "|"); } strcat(cmd, "'"); //printf("cmd = %s\n", cmd);}int main(int argc, char **argv){ DIR *dp; struct dirent *dirp; int dir_num = 0; // /proc 目录下总的文件数 int i = 0; int j = 0; int ret = 0; int pid_min = 0; // pid 进程最大值 int pid_max = 0; // pid 进程最大值 int pid = 0; int temp_pid = 0; int rd_flag = 0; // 读取的方式标记 int cycle_flag = 0; // 循环读取标记 char dir_name[DIR_MAX][DIR_NAME_MAX]; // 存放 /proc 目录下所有的文件名 char temp_name[DIR_NAME_MAX]; char process_name[DIR_NAME_MAX]; // 进程名称 char status_path[DIR_NAME_MAX]; // 保存 /proc/[pid]/status 的路径 char cmd[CMD_NAME_MAX]; // 执行的命令 rd_flag = GetRdFlag(argc, argv); if(rd_flag <= 1) { ShowHelp(); return 0; } //printf("rd_flag = %d\n", rd_flag); // 获取循环标记 cycle_flag = atoi(argv[2]); //printf("cycle_flag = %d\n", cycle_flag); if(cycle_flag < 0 || cycle_flag > 1) { printf("cycle_flag error, please check it!\n"); return -1; } switch(rd_flag) { case 3: strcpy(process_name, argv[4]); //printf("process = %s\n", process_name); break; case 4: pid = atoi(argv[4]); //printf("pid = %d\n", pid); break; case 5: pid_min = atoi(argv[4]); pid_max = atoi(argv[5]); //printf("pid_min = %d, pid_max = %d\n", pid_min, pid_max); if(pid_min > pid_max){ printf("pid range error, please check it\n"); return -1; } break; default: break; } if((dp = opendir(PROC_DIR_PATH)) == NULL) printf("Can't open %s\n", PROC_DIR_PATH); while((dirp = readdir(dp)) != NULL) { strcpy(&dir_name[dir_num++][0], dirp->d_name); } //printf("dir_num = %d\n", dir_num); do { for(i=0; i<dir_num; i++) { strcpy(temp_name, &dir_name[i][0]); ret = isStringNum(temp_name); if(ret == 1) { // 获取 /proc/[pid] 成功 temp_pid = atoi(temp_name); //printf("temp_pid = %d\n", temp_pid); if(rd_flag == 3) { ret = isProcessMatchPid(temp_name, argv[4]); if(ret > 0) { //printf("Process match pid ok\n"); SetCmd(argc, argv, status_path, cmd, temp_name); system(cmd); printf("\n"); break; } } else if(rd_flag == 4 && temp_pid == pid) { // 通过 pid 来 cat 状态 SetCmd(argc, argv, status_path, cmd, temp_name); system(cmd); printf("\n"); break; }else if(rd_flag == 5 && (temp_pid >= pid_min && temp_pid <= pid_max)) { // 通过 pid 范围 cat 状态 SetCmd(argc, argv, status_path, cmd, temp_name); system(cmd); printf("\n"); } } } sleep(1); printf("===================\n"); }while(cycle_flag == 1); closedir(dp); return 0;}#endif
- 通过 /proc/[pid]/ 查看进程状态
- 查看进程状态/proc/pid/stat
- 查看进程状态/proc/pid/stat
- 通过/proc/pid./status查看进程信息
- linux下查看进程的状态 /proc/[pid]/status
- cat /proc/$PID/status进程状态
- 查看进程所占内存/proc/[pid]/statm踩坑记
- Linux通过PID查看进程完整信息
- Linux通过PID查看进程完整信息
- 通过进程pid查看文件安装路径
- Linux通过PID查看进程完整信息
- Linux通过PID查看进程完整信息
- Linux通过PID查看进程完整信息
- /proc/pid进程相关说明
- 进程内存信息 /proc/[pid]/maps /proc/[pid]/smaps /proc/[pid]/status
- 查看进程pid/tid
- 查看进程pid,杀死进程
- 通过Linux内核观察/proc/pid/statm
- 异常
- 在Ubuntu 16.04 中将应用添加到系统服务中
- 11.05周日
- linux 命令
- js笔记2
- 通过 /proc/[pid]/ 查看进程状态
- 新生活,新开始
- Ajax跨域的那些坑
- Spark学习之(三) 小例子
- Python 函数相关总结
- Dockerfile 创建简单镜像
- 快速搭建AMP开发环境
- 数据库之行列转换
- 【软考之旅】编译解释程序