菜鸟笔记
提升您的技术认知

lru页面回收-ag真人游戏

内存回收算法总是会在一定的时间将一些内存回收, 内存回收算法是通过lru链表对page页面进行管理的,对于那些新的页面会将其插入到lru链表头,回收时将返回lru链表末尾的元素,代表老化程度最高的页面

typedef struct pglist_data {
  
...
       /* fields commonly accessed by the page reclaim scanner */                                                                                              
        
        /*
         * note: this is unused if memcg is enabled.                                                                                                            
         *
         * use mem_cgroup_lruvec() to look up lruvecs.                                                                                                          
         */
        struct lruvec           __lruvec;
...

内存页回收的管理是以node为单位的,pglist_data 中会包含一个struct lruvec数组

struct lruvec {
  
        struct list_head                lists[nr_lru_lists];
...

这个struct lruvec数组包含了nr_lru_lists个lru链表元素,这些链表元素定义如下,每个链表将放置不同类别的page,相关类别由enum lru_list定义

enum lru_list {
  
        lru_inactive_anon = lru_base,
        lru_active_anon = lru_base   lru_active,
        lru_inactive_file = lru_base   lru_file,
        lru_active_file = lru_base   lru_file   lru_active,
        lru_unevictable,
        nr_lru_lists
};
//mm/swap.c
/*                                                                                                                                                              
 * the following struct pagevec are grouped together because they are protected                                                                                 
 * by disabling preemption (and interrupts remain enabled).                                                                                                     
 */                                                                                                                                                             
struct lru_pvecs {
                                                                                                                                                
        local_lock_t lock;                                                                                                                                      
        struct pagevec lru_add;                                                                                                                                 
        struct pagevec lru_deactivate_file;                                                                                                                     
        struct pagevec lru_deactivate;                                                                                                                          
        struct pagevec lru_lazyfree;                                                                                                                            
#ifdef config_smp                                                                                                                                               
        struct pagevec activate_page;                                                                                                                           
#endif                                                                                                                                                          
};                                                                                                                                                              
static define_per_cpu(struct lru_pvecs, lru_pvecs) = {
                                                                                                            
        .lock = init_local_lock(lock),                                                                                                                          
};

内核同时定义了struct lru_pvecs , 它包含了5个struct pagevec变量

struct pagevec {
                                                                                                                                                  
        unsigned char nr;                                                                                                                                       
        bool percpu_pvec_drained;                                                                                                                               
        struct page *pages[pagevec_size];                                                                                                                       
};

这些struct pagevec变量实际是用来管理具体的page页面的
如上相关结构体有如下的对应关系

/**
 * lru_cache_add - add a page to a page list
 * @page: the page to be added to the lru.
 *
 * queue the page for addition to the lru via pagevec. the decision on whether
 * to add the page to the [in]active [file|anon] list is deferred until the
 * pagevec is drained. this gives a chance for the caller of lru_cache_add()
 * have the page added to the active list using mark_page_accessed().
 */
void lru_cache_add(struct page *page)
{
  
        struct pagevec *pvec;
        vm_bug_on_page(pageactive(page) && pageunevictable(page), page);
        vm_bug_on_page(pagelru(page), page);
        get_page(page);
        local_lock(&lru_pvecs.lock);
        pvec = this_cpu_ptr(&lru_pvecs.lru_add);
        if (!pagevec_add(pvec, page) || pagecompound(page))
                __pagevec_lru_add(pvec);
        local_unlock(&lru_pvecs.lock);
}
export_symbol(lru_cache_add);
  1. pagevec_add:实际就是将页面加入到struct lru_pvecs的某个struct pagevec中,这里实际是加入到lru_pvecs.lru_add中,并返回当前struct pagevec可管理的剩余的page个数
/*                                                                                                                                                              
 * add a page to a pagevec.  returns the number of slots still available.                                                                                       
 */                                                                                                                                                             
static inline unsigned pagevec_add(struct pagevec *pvec, struct page *page)                                                                                     
{
                                                                                                                                                                 
        pvec->pages[pvec->nr  ] = page;                                                                                                                         
        return pagevec_space(pvec);                                                                                                                             
}
  1. __pagevec_lru_add:如果struct pagevec可管理的剩余的page个数为0,则需要执行__pagevec_lru_add,它实际是将已经满的struct pagevec中的page页迁移到某个lru链表中去,至于迁移到哪个lru链表,由当前page所处的struct pagevec类别 以及page自身的flags变量决定,迁移时会考虑到各个页面的老化程度,越老的页面越会靠近lru链表的后面,经典内存回收算法将扫描lru链表选取相应的页面回收
#define lru_to_page(head) (list_entry((head)->prev, struct page, lru))

将返回链表的最后一个元素,它代表老化程度最高的一个page

网站地图