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

时间:2015-06-09 23:05:27

标签: linux memory-management

我想计算单个进程的内存使用量。经过一些研究后,我发现了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。 我可以通过使用smaps来获得这两个值吗?这个价值是否正确? 另外,我想以百分比形式返回该值。

2 个答案:

答案 0 :(得分:7)

我认为statmsmaps的近似简化,获得的代价更高。在我查看来源后,我得出了这个结论:

smaps

您在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);

那么/fs/proc/task_mmu.c中的回调smaps_pte_range是做什么的呢? 在某些情况下,它会调用smaps_pte_entrysmaps_pmd_entry,其中两个都会调用statm_account(),而resident会升级task_mmu.c大小!所有这些功能都在已经链接的statm中定义,因此我没有发布相关的代码片段,因为它们可以在链接的源中轻松查看。

PTE代表Page Table Entry,PMD代表Page Middle Directory。所以基本上我们遍历与给定进程关联的页面条目,并根据具体情况更新RAM使用情况。

statm

您在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; } 中看到的信息在/fs/proc/array.c中定义:

resident

这一次,task_statmtask_mmu.c填充。这个有两个实现,一个在/fs/proc/task_mmu.c,第二个在/fs/proc/task_nomm.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_FILEPAGES

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

结论

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

最重要的部分是,statm每次以独立方式收集数据时,statm使用在进程生命周期中递增或递减的计数器。有很多地方需要进行簿记,也许有些地方不会像他们应该那样升级柜台。这就是为什么IMO smaps不如smaps,即使它需要较少的CPU周期来完成。

请注意,这是我根据常识得出的结论,但我可能错了 - 也许在计数器递减和递增中没有内部不一致,相反,它们可能会计算某些页面的不同于$newArray = array(); $dates = array(); foreach($array as $entry) { $newArray[$entry['id']][$entry['hour']][$entry['date']]= $entry['total']; if(!in_array($entry['date'], $dates)) $dates[] = $entry['date']; } sort($dates); echo "id hour ". $dates[0] . " " . $dates[1] . " " . "difference"."\n"; foreach($newArray as $id => $hours) foreach($hours as $hour => $entry) echo $id ." " . $hour . " " . $entry[$dates[0]] . " " . $entry[$dates[1]] . " " . ($entry[$dates[1]] - $entry[$dates[0]]) . "\n"; 。在这一点上,我认为将它带给一些经验丰富的内核维护者是明智的。

答案 1 :(得分:0)

我建议通过' top'命令行源代码。它从/ proc获取所有信息,因此jt可能是一个很好的参考。