gpt4 book ai didi

Linux 操作系统 :/proc/[pid]/smaps vs/proc/[pid]/statm

转载 作者:IT王子 更新时间:2023-10-29 00:48:02 34 4
gpt4 key购买 nike

我想计算单个进程的内存使用量。因此,经过一些研究后,我发现了 smaps 和 statm。

首先什么是smaps和statm?有什么区别?

statm 有一个 RSS 字段,在 smaps 中我总结了所有 RSS 值。但是对于同一个过程,这些值是不同的。我知道 statm 以页面为单位进行测量。出于比较目的,我将该值转换为 kb,就像在 smaps 中一样。但这些值并不相等。为什么这两个值不同,即使它们代表同一进程的 rss 值?

statm
232214 80703 7168 27 0 161967 0 (measured in pages, pages size is 4096)

smaps
Rss 1956

我的目标是计算单个进程的内存使用情况。我对两个值感兴趣。 USS 和 PSS。我可以仅使用 smap 获得这两个值吗?该值是否正确?另外,我想以百分比的形式返回该值。

最佳答案

我认为 statmsmaps 的近似简化,获取它的成本更高。我看了源码后得出了这个结论:

map

您在smaps 中看到的信息定义在/fs/proc/task_mmu.c 中:

static int show_smap(struct seq_file *m, void *v, int is_pid)
{
(...)

struct mm_walk smaps_walk = {
.pmd_entry = smaps_pte_range,
.mm = vma->vm_mm,
.private = &mss,
};

memset(&mss, 0, sizeof mss);
walk_page_vma(vma, &smaps_walk);
show_map_vma(m, vma, is_pid);

seq_printf(m,
(...)
"Rss: %8lu kB\n"
(...)
mss.resident >> 10,

mss中的信息被/mm/pagewalk.c中定义的walk_page_vma使用.但是,mss 成员 resident 没有填入 walk_page_vma - 相反,walk_page_vma 调用 中指定的回调smaps_walk:

.pmd_entry = smaps_pte_range,
.private = &mss,

像这样:

  if (walk->pmd_entry)
err = walk->pmd_entry(pmd, addr, next, walk);

那么我们的回调是什么,smaps_pte_range in /fs/proc/task_mmu.c , 做?它在某些情况下调用 smaps_pte_entrysmaps_pmd_entry,其中都调用 statm_account(),这反过来......升级 resident 尺寸!所有这些函数都在已链接的 task_mmu.c 中定义,因此我没有发布相关代码片段,因为它们可以在链接的源代码中轻松看到。

PTE 代表页表条目,PMD 是页中间目录。所以基本上我们遍历与给定进程关联的页面条目并根据情况更新 RAM 使用情况。

统计

您在statm 中看到的信息定义在/fs/proc/array.c 中:

int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)
{
unsigned long size = 0, resident = 0, shared = 0, text = 0, data = 0;
struct mm_struct *mm = get_task_mm(task);

if (mm) {
size = task_statm(mm, &shared, &text, &data, &resident);
mmput(mm);
}
seq_put_decimal_ull(m, 0, size);
seq_put_decimal_ull(m, ' ', resident);
seq_put_decimal_ull(m, ' ', shared);
seq_put_decimal_ull(m, ' ', text);
seq_put_decimal_ull(m, ' ', 0);
seq_put_decimal_ull(m, ' ', data);
seq_put_decimal_ull(m, ' ', 0);
seq_putc(m, '\n');
return 0;
}

这一次,residenttask_statm填充。这个有两个实现,一个在/fs/proc/task_mmu.c中。在 /fs/proc/task_nomm.c 中排名第二.由于它们几乎肯定是相互排斥的,因此我将重点介绍 task_mmu.c 中的实现(其中还包含 task_smaps)。在这个实现中我们看到

unsigned long task_statm(struct mm_struct *mm,
unsigned long *shared, unsigned long *text,
unsigned long *data, unsigned long *resident)
{
*shared = get_mm_counter(mm, MM_FILEPAGES);
(...)
*resident = *shared + get_mm_counter(mm, MM_ANONPAGES);
return mm->total_vm;
}

它查询一些计数器,即 MM_FILEPAGESMM_ANONPAGES。这些计数器在对内存的不同操作期间被修改,例如在 /mm/memory.c 定义的 do_wp_page .所有的修改似乎都是由位于/mm/ 中的文件完成的,而且似乎有很多,所以我没有在这里包含它们。

结论

smaps 对所有引用的内存区域进行复杂的迭代,并使用收集到的信息更新 resident 大小。 statm 使用已经由其他人计算的数据。

最重要的部分是 smaps 每次都以独立的方式收集数据,而 statm 使用在进程生命周期中递增或递减的计数器。需要做记账的地方很多,也许有些地方并没有按照应有的方式升级柜台。这就是为什么 IMO statm 不如 smaps,即使它需要更少的 CPU 周期来完成。

请注意,这是我根据常识得出的结论,但我可能是错的 - 也许在计数器递减和递增方面没有内部不一致,相反,它们可能以不同于 smaps。在这一点上,我认为将它交给一些有经验的内核维护者是明智的。

关于Linux 操作系统 :/proc/[pid]/smaps vs/proc/[pid]/statm,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30744333/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com