内存管理-31-每进程内存统计-2-/proc/pid/statm
基于msm-5.4
一、初探
1. 打印格式
# cat /proc/593/statm //非内核线程 2826695 22403 17848 1420 0 12717 0 //以 PAGE_SIZE 为单位 # cat /proc/187/statm //内核线程 0 0 0 0 0 0 0
打印成员介绍:
1: size: 打印的是 mm->total_vm 的值,表示任务占用虚拟地址空间大小,单位PAGE_SZIE。对应status文件节点的 VmSize 除以4后的值。
2: resident: 打印的是 MM_FILEPAGES + MM_SHMEMPAGES + MM_ANONPAGES, 表示任务正在使用的物理内存的大小,对应status文件节点的 VmRSS 除以4后的值。
实测:
# cat /proc/612/status | grep VmRSS; cat /proc/612/statm VmRSS: 69300 kB 2844270 17325 13092 1431 0 13044 0 //69300kB/4=17325 pages
3: shared: 打印的是 MM_FILEPAGES + MM_SHMEMPAGES,表示任务的共享页数。
4: text: 任务代码段虚拟内存大小,打印的是 mm->end_code - mm->start_code 对应的页面个数,对应status文件节点的 VmExe 除以4后的值。
5: 打印的是固定0值。
6: data: 打印的是 mm->data_vm + mm->stack_vm 的值。
7: 打印的是固定0值。
2. 成员介绍
在 Linux 系统中,/proc/<pid>/statm 文件用于提供该进程的内存使用状态简报,单位是“页面数”。在 cat /proc/1/statm,输出的 7 个数字 从左到右依次对应的字段含义如下:
565498 3110 2104 481 0 5775 0 │ │ │ │ │ │ │ size resident shared text lib data dirty
(1) size: 虚拟内存总大小(VSS/VSZ)。含义:进程当前申请并占用的总虚拟地址空间大小。计算:565498 * 4 = 2,261,992 = 2.15 GB。这只是进程“宣称”要使用的虚拟内存空间,不代表实际物理内存消耗。
(2) resident: 实际物理内存占用(RSS)。含义:进程当前真正常驻在物理内存(RAM)中的页面数,包含共享库占用的物理内存。计算:3110 * 4KB = 12,440KB = 12.15MB。这是评估进程内存消耗的最核心指标。当前 init 进程实际只吃掉了 12MB 的物理内存。
(3) shared: 共享内存页面数(SHR)。含义:进程占用的物理内存中,有多少页面是与其他进程共享的(例如通过 mmap 共享的 libc.so 等基础系统库,或者显式创建的共享内存块)。计算:2104 * 4K = 8.22MB。提高 shared 的比例是好现象,说明多个系统服务在复用同一套公共库,没有重复浪费物理内存。
(4) text: 代码段大小。含义:进程自身可执行二进制代码(包含程序逻辑指令)所占用的编译好的代码段页面数。
(5) lib: 库文件页面数。备注:该字段在 Linux 2.6 及以后的现代内核中已经废弃,固定输出为 0。可以不用关注。
(6) data: 数据段与堆栈大小。含义:进程的虚拟地址空间中,专门用于动态分配的数据结构(如堆 Heap、栈 Stack、BSS 段、数据段)的虚拟页面总数。
(7) dirty: 脏页(Dirty Pages)数量备注:在 Linux 2.6 及更高版本的内核中也已经废弃,固定输出为 0。同样无需关注。
3. 实现
static const struct pid_entry tgid_base_stuff[] = { //fs/proc/base.c ONE("statm", S_IRUGO, proc_pid_statm), }; static const struct pid_entry tid_base_stuff[] = { //fs/proc/base.c ONE("statm", S_IRUGO, proc_pid_statm), }; int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) //proc/array.c { unsigned long size = 0, resident = 0, shared = 0, text = 0, data = 0; /* 若是内核线程返回NULL */ struct mm_struct *mm = get_task_mm(task); if (mm) { size = task_statm(mm, &shared, &text, &data, &resident); mmput(mm); } seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n", size, resident, shared, text, data); return 0; } unsigned long task_statm(struct mm_struct *mm, unsigned long *shared, unsigned long *text, unsigned long *data, unsigned long *resident) //proc/task_mmu.c { /* mm->rss_stat.count[MM_FILEPAGES] + mm->rss_stat.count[MM_SHMEMPAGES] */ *shared = get_mm_counter(mm, MM_FILEPAGES) + get_mm_counter(mm, MM_SHMEMPAGES); /* mm->end_code 向上圆整,mm->start_code 向下圆整,以 PAGE_SIZE 为单位 */ *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> PAGE_SHIFT; *data = mm->data_vm + mm->stack_vm; /* MM_FILEPAGES + MM_SHMEMPAGES + MM_ANONPAGES */ *resident = *shared + get_mm_counter(mm, MM_ANONPAGES); /* 返回值是总占用的虚拟内存 */ return mm->total_vm; }
3. 实验
(1) 通过这个文件看,主线程的和各个子线程的cat出来的值是完全一样的
P=593; cat /proc/$P/statm; for T in `ls /proc/$P/task/`; do cat /proc/$P/task/$T/statm; done;
(2) 累加所有进程的第二个成员
TDIR=/proc; let RSS=0; for P in `ls $TDIR | grep "^[0-9]"`; do if [ -f $TDIR/$P/statm ]; then TEP=`cat $TDIR/$P/statm | awk '{print ($2)}'`; RSS=$((RSS + TEP)); fi; done; RSS=$((RSS * 4)); echo RSS=$RSS"KB";
posted on 2024-08-26 21:53 Hello-World3 阅读(285) 评论(0) 收藏 举报
浙公网安备 33010602011771号