do_try_to_free_pages

/*
 * This is the main entry point to direct page reclaim.
 *
 * If a full scan of the inactive list fails to free enough memory then we
 * are "out of memory" and something needs to be killed.
 *
 * If the caller is !__GFP_FS then the probability of a failure is reasonably
 * high - the zone may be full of dirty or under-writeback pages, which this
 * caller can't do much about.  We kick the writeback threads and take explicit
 * naps in the hope that some of these pages can be written.  But if the
 * allocating task holds filesystem locks which prevent writeout this might not
 * work, and the allocation attempt will fail.
 *
 * returns: 0, if no pages reclaimed
 *      else, the number of pages reclaimed
 */

这是个超级重要的函数,是回收页的主逻辑。

do_try_to_free_pages -> shrink_zones -> shrink_node -->shrink_node_memcg -->

mem_cgroup_soft_limit_reclaim

进行内存回收的时候,balance_pgdat和shrink_zones的时候,都是先去回收soft_limit

只在内存回收的时候起作用,只有全局回收的时候才会去

mem_cgroup_soft_limit_reclaim --> mem_cgrop_soft_reclaim -->mem_cgroup_shrink_node-->shrink_node_memcg--> ... -->shrink_page_list

最终都会计入

所以shrink_nodes是真正的shrink page的地方,在shrink page的地方,只会去回收那些clean的页,在这个函数中先会回收mem soft limit,然后会去刷全局的page

shrink_zones只在一个地方调用,就是do_write_data_pages,这里是所有直接内存回收的地方,包括page_alloc,包括memcgroup缩容,都是在这里, do_try_to_free_pages这里是,这是直接内存回收的路径,① kwapd_shrink_node--->shrink_node-->shrink_node_memcg

shrink_node_memcg函数就是所有函数的殊途同归的地方,shrink_node是啥子呢?

② node_reclaim-->__node_reclaim-->shrink_node 这个是快速回收方法, shrink_node就是

③ do_try_to_free_pages --> shrink_nodes  --> shrink_node

所以shrink_node从三个地方来,所以地方一是慢速回收,地方二是用do_try_to_free_pages慢速回收,再就是后台回收了,前两者都是全局的回收,do_try_to_free_pages就包括全局回收,也包括cgroup回收啦,mem_cgroup_soft_limit_reclaim就完全是和主流的回收流程并行的一套回收逻辑了。咋说呢?mem_cgroup_soft_limit_recliam的出发点有两个1> balance_pgdat 2>使用在使用shrink_zones的时候,do_try_to_free_pages的时候要用,并且在是在全局回收的时候调用。

所以我们就知道了,soft_limit_reclaim在什么时候起作用呢?就是在全局内存内存回收的时候。也就是在上图中的1)和3)两条线,机型内存回收时,如果是全局的回收,在调用最后的shrink_node_memcg之前

shrink_zones直接内存回收

【疑问一:】那page的lru到底是放在了cgroup的lru列表里,还是放到了全局的lru列表中去呢?

shrink_node_memcg 函数中,如果没有cgroup,那么就使用pgdat->lruvec全局的lru的全局表,如果否则放到了cgroup的lru表中,啥时候把页放到lru中呢?看函数__page_cache_alloc,中有mem_cgroup_try_charge

memcg_kmem_charge_memcg,啥时候

memory_cgroup_commit_charge --> commit_charge ---> unlock_page_lru 是不是所有的lru表并不是所有的页全都在lru表上的呢

函数mm/filemap.c __add_to_page_cache_locked函数中会charge page:

lru_cache_add函数是把page增加到lru链表中

add_to_cache_lru 函数中增加到lru链表中去,

page-cache增加页:add_to_cache_lru函数中1)__add_to_cache_lru, 2) lru_cache_add

普通匿名页:lru_cache_add_active_or_unevictable函数中间接调用lru_cache_add

在lru_cache_add函数之前已经调用过了函数mem_cgroup_commit_charge函数,这个函数中已经把 page->mem_cgroup = memcg; 做了这样的处理了。

这是在page-cache中,所以肯定的是,lru有全局表有每个cgroup的表,这些页都是分布在不同的表中。

那么这个page不同的lru列表,shrink的时候是按照LRU表来shrink的,但是页的lru链表是放到不同的cgroup里的,如果遍历这些cgroup表呢?

/**
 * mem_cgroup_commit_charge - commit a page charge
 * @page: page to charge
 * @memcg: memcg to charge the page to
 * @lrucare: page might be on LRU already
 * @compound: charge the page as compound or small page
 *
 * Finalize a charge transaction started by mem_cgroup_try_charge(),
 * after page->mapping has been set up.  This must happen atomically
 * as part of the page instantiation, i.e. under the page table lock
 * for anonymous pages, under the page lock for page and swap cache.
 *
 * In addition, the page must not be on the LRU during the commit, to
 * prevent racing with task migration.  If it might be, use @lrucare.
 *
 * Use mem_cgroup_cancel_charge() to cancel the transaction instead.
 */

5423 void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg, bool lrucare, bool compound)

memory_cgroup_soft_limit在哪里用呢?首先是kwapd_shrink_node函数里,在调用shrink_node之前,会首先回收soft_limit超过阈值的页,再就是在函数shrink_zones中,shirik_zones只在一个地方使用do_try_to_free_pages,在强制内存回收的时候,如果是全局的强制内存回收,还是先想着想着回收内存中,

【疑问二:为啥干净的页就能够】

全局管理有个好处,LRU是全局管理,大家一份,但是现在

void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg,

shrink_node-> shrink_node_memcg

原文地址:https://www.cnblogs.com/honpey/p/9054150.html