一、内存页面回收

参考:http://www.wowotech.net/memory_management/233.html

内核会回收很少使用的内存页面来保证系统持续有内存使用。页面的回收方式有三种

  • 页回写:如果一个很少使用的页的后备存储器是一个块设备(例如文件映射),则可以将内存直接同步到块设备,腾出的页面可以被重用。
  • 页交换:如果页面没有后备存储器,则可以交换到特定swap分区,再次被访问时再交换回内存。
  • 页丢弃:如果页面的后备存储器是一个文件,但文件内容在内存不能被修改(例如可执行文件),那么在当前不需要的情况下可直接丢弃。

触发页面回收的时机如下图所示:

 

当触发页面回收时,内核对下列分配的内存页进行回收处理:

  • LRU列表中的页框
  • slab缓存:所有注册到shrinker_list的shrinker都会被触发回收内存。

参考mm/vmscan.c

内核中定义了一个列表shrinker_list,外部通过register_shrinker、unregister_shrinker向该列表添加和移除shrinker。

shrinker的定义如下:

 1 /*
 2  * A callback you can register to apply pressure to ageable caches.
 3  *
 4  * @count_objects should return the number of freeable items in the cache. If
 5  * there are no objects to free or the number of freeable items cannot be
 6  * determined, it should return 0. No deadlock checks should be done during the
 7  * count callback - the shrinker relies on aggregating scan counts that couldn't
 8  * be executed due to potential deadlocks to be run at a later call when the
 9  * deadlock condition is no longer pending.
10  *
11  * @scan_objects will only be called if @count_objects returned a non-zero
12  * value for the number of freeable objects. The callout should scan the cache
13  * and attempt to free items from the cache. It should then return the number
14  * of objects freed during the scan, or SHRINK_STOP if progress cannot be made
15  * due to potential deadlocks. If SHRINK_STOP is returned, then no further
16  * attempts to call the @scan_objects will be made from the current reclaim
17  * context.
18  *
19  * @flags determine the shrinker abilities, like numa awareness
20  */
21 struct shrinker {
22         unsigned long (*count_objects)(struct shrinker *,
23                                        struct shrink_control *sc);
24         unsigned long (*scan_objects)(struct shrinker *,
25                                       struct shrink_control *sc);
26 
27         int seeks;      /* seeks to recreate an obj */
28         long batch;     /* reclaim batch size, 0 = default */
29         unsigned long flags;
30 
31         /* These are for internal use */
32         struct list_head list;
33         /* objs pending delete, per node */
34         atomic_long_t *nr_deferred;
35 };

lowmemorykiller就是通过向shrinker_list中注册shrinker。

当内存不足时kswapd线程会遍历shrinker_list链表,并回调已注册的shrinker函数来回收内存page,kswapd还会周期性唤醒来执行内存操作。每个zone维护active_list和inactive_list链表,内核根据页面活动状态将page在这两个链表之间移动,最终通过shrink_slab和shrink_zone来回收内存页

 

posted on 2018-03-17 10:16  ruby.dongyu  阅读(317)  评论(0)    收藏  举报