[/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/meminfo 之谜]http://linuxperf.com/?p=142
在这篇文章中 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]/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 (tracing
stop)", "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 are
pages that can't be moved because something needs to
directly access physical memory.
* VmHWM: Peak resident set size ("high water mark").
* VmRSS: Resident set size. Note that the value here is the
sum of RssAnon, RssFile, and RssShmem.
* RssAnon: Size of resident anonymous memory. (since Linux
4.5).
* RssFile: Size of resident file mappings. (since Linux 4.5).
* RssShmem: Size of resident shared memory (includes System V
shared memory, mappings from tmpfs(5), and shared anonymous
mappings). (since Linux 4.5).
* VmData, VmStk, VmExe: Size of data, stack, and text
segments.
* 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 private
pages; shmem swap usage is not included (since Linux
2.6.34).
* Threads: Number of threads in process containing this
thread.
如果我们只想要获取其中某几个参数的值,可以使用命令:
#cat /proc/1/status | grep -E 'VmSize|VmRSS'
有这么一个需求:要统计各个进程中占用的物理内存的大小,我总不能一条条去执行cat命令吧,于是我们可以写一个应用程序循环读取每个进程的某个状态值。于是就有了下面的 rdstatus 应用程序
这些内容在内核代码中:
中实现。
rdstatus.c 只能用来获取 /proc/[pid]/status
中的内容。通过读取 /proc
目录下的所有文件,然后提取其中[pid]
的目录,获取到 /proc/[pid]/status
的路径,再组合成 cmd
命令传递给system()
执行。
#if 1
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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/
在头文件中定义了两种主要的数据类型。
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);
/* 返回目录流的当前位置 */
#endif
int 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= 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 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 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