memory.usage_in_bytes与rss内存统计不一致

Time: 六月 28, 2015
Category: cgroup

最近线上发现一个问题。一个用户在做resize操作的时候失败了,resize的主要动作是将内存阈值从45G调整到50G,按理来说这个调整是可行的,但实际执行时出现了问题。执行器报错如下:

Cgroups: failed to write memory.excess_mode:
16: Device or resource busy

用户的解释说,通过top统计到container内的rss进程只使用了20G左右,并没有超过45G。但是我们看memory.usage_in_bytes的统计时,container内存已经达到了90G。为什么memory.usage_in_bytes和rss会不一致呢?

原因是因为,cgroup的memory在统计内存时,把page cache也统计进去了,而top看到的rss,是不包含page cache的。

mem_cgroup统计内存用的几个函数是:

extern int mem_cgroup_newpage_charge(
    struct page *page, struct mm_struct *mm, gfp_t gfp_mask);

/* for swap handling */
extern void mem_cgroup_commit_charge_swapin(struct page *page,
    struct mem_cgroup *memcg);

extern int mem_cgroup_cache_charge(struct page *page,
    struct mm_struct *mm, gfp_t gfp_mask);

由于mem_cgroup_newpage_charge()和mem_cgroup_commit_charge_swapin()函数最终都会调 用 mem_cgroup_charge_common(),所以本质上,mem_cgroup统计内存只有两个API,其中 newpage_charge()对应匿名页,cache_charge()对应file page cache

top中的rss内存是通过get_mm_rss()来获取的:

static inline unsigned long get_mm_rss(struct mm_struct *mm)
{
    return get_mm_counter(mm, MM_FILEPAGES) +
        get_mm_counter(mm, MM_ANONPAGES);
}

而mm_counter对应的统计函数是:

inc_mm_counter_fast(mm, MM_ANONPAGES);
inc_mm_counter_fast(mm, MM_FILEPAGES);

但是page cache在创建的时候,调用了mem_cgroup_cache_charge()而没有调用inc_mm_counter_fast()增加相应的计数器。

具体可以关注一下 add_to_page_cache_locked() 函数

4 comments to “memory.usage_in_bytes与rss内存统计不一致”

  1. richard说道:

    hi 你好,我也遇到了类似的问题。我的问题是rss值比cgroup中memory.usage_in_bytes要大。根据本文的分析rss不包含page_cache应该更小才对。

    ps,我的内核版本为3.13.6

    • fangdong说道:

      rss和memory.usage_in_bytes的统计方式,统计时机都是有很大不同的。例如,usage_in_bytes是从进程写到cgroup后才开始统计的,可能你的进程之前rss就很大。又如,将一个进程从一个cgroup中去掉,usage_in_bytes并不会减少之前已经统计过的内存,加入到另外一个cgroup后,另外一个cgroup也是从新开始统计。

      memory.usage_in_bytes并不能严格反映当前cgroup内存使用的实际情况

Leave a Comment