Linux 内存页面回收

页面回收内容感觉非常复杂,主要原因在于分析者,把其复杂化。
1.内存页面
页面回收实际就是回收相应缓存, 因为系统为了性能有效,使用大量缓存。 这些缓存占用大量内存。 当系统内存短缺时,可以回收相应页面。如果不一致话,首先要把缓存内容,刷新到外部存储中。缓存页面可分为:可压缩的缓存(目录和inode节点占用内存页面), slab, 交换高速缓存(缓存交换分区的页面),页高速缓存(缓存文件内容的页面)。由于可压缩的缓存和 slab占用页面,可有专门函数进行回收,所以只讨论其他可回收的页面。
由此可见页面回收主要就是交换高速缓存与页高速缓存页面的回收。系统中匿名映射对应于交换高速缓存, 文件映射对应于页高速缓存页面, 可以说存在第三种磁盘缓冲区页(实际包含在页高速缓存页面), 这些缓冲区信息包含(磁盘inode, 超级块等设备信息数据, 因为这些数据不是已文件方式组织,以块方式存放在硬盘), 我们讨论页面回收就是回收这三方面.
为了加深理解,了解进程内存映射。内存要么缓存文件,要么缓存匿名数据
# pmap  24044
24044:   bash
0000000000400000    852K r-x--  /bin/bash
00000000006d4000     40K rw---  /bin/bash
00000000006de000     20K rw---    [ anon ]
0000000002509000    396K rw---    [ anon ]
00007ffb3c562000     48K r-x--  /lib64/libnss_files-2.12.so
00007ffb3c56e000   2048K -----  /lib64/libnss_files-2.12.so
00007ffb3c76e000      4K r----  /lib64/libnss_files-2.12.so

2.页面回收实现
页面回收实现,实际就是断开其他数据结构对于页描述的引用,同时断开页描述符中相应字段对于其他结构引用。一句话双方数据结构引用相互断开。
页描述符数据结构:
struct page {
        unsigned long flags;            /* Atomic flags, some possibly  updated asynchronously */
        atomic_t _count;                /* Usage count, see below. */
         atomic_t _mapcount;     /* Count of ptes mapped in mms,
                                               * to show when page is mapped
                                                  * & limit reverse map searches.
                                                */
        union {
            struct {
                unsigned long private;          /* Mapping-private opaque data:
                                                 * usually used for buffer_heads
                                                 * if PagePrivate set; used for
                                                 * swp_entry_t if PageSwapCache;
                                                 * indicates order in the buddy
                                                 * system if PG_buddy is set.
                                                 */
                struct address_space *mapping;  /* If low bit clear, points to
                                                 * inode address_space, or NULL.
                                                 * If page mapped as anonymous
                                                 * memory, low bit is set, and
                                                 * it points to anon_vma object:
                                                 * see PAGE_MAPPING_ANON below.
                                                 */
            };

        struct list_head lru;           /* Pageout list, eg. active_list
                                                 * protected by zone->lru_lock !
                                                  */
  }
count: 反映物理页使用计数, 0表示空闲,没人用,释放。最简单内存回收实际可以这样实现,仅仅标记其0就可以^_^。
flags: 反映物理页状态,例如物理页脏,意味着物理内存页与后端设备内容不一致。如果不一致,页面回收该如何处理呢?
mapcount: 反映有多少个进程页表项指向该物理页, 如果多个页表项引用话,页面回收该如何处理呢?
private: 反映有无缓存区,如果有话,页面回收该如何处理呢?
mapping:反映是页高速缓存还是交换高速缓存


特别注意: private与mapping为union, 即两者不可兼得。

3.页面回收代码分析

过程如下:
一)页面统一处理:
1 如果多个页表项引用话,.断开对于页面引用。
2.页面内容不一致,进行页面回写

二)根据页面缓存内容类型,分别处理:
3.现在判断该页面磁盘缓冲区,还是交换高速缓存,还是页面高速缓存,当然只能为其一。
4.磁盘缓冲区:从缓冲区头,断开对页面指向。
5.交换高速缓存:从交换分区基树中,删除该页面。
6.页面高速缓存:从节点基树中,删除该页面。

三)释放页面,标记物理页使用计数为0等
7.收集要释放页面,之后统一存放内存分配区,释放完成。
static unsigned long shrink_page_list(struct list_head *page_list,
                                        struct scan_control *sc,
                                        enum pageout_io sync_writeback)
{
   while (!list_empty(page_list)) {
//如果有多少个进程页表项指向该物理页, 如果多个页表项引用话, 需要断开其映射。
//实际就是断开指向页描述符,设置相应进程页表项为NULL,删除页描述所指向vma
 if (page_mapped(page) && mapping) {
                        switch (try_to_unmap(page, TTU_UNMAP)) {
                        case SWAP_SUCCESS:
                                ; /* try to free the page below */
                        }
                }
//如果页描述符所指向页面脏(与硬盘上数据不一致)的话,所以回收之前,其内容写回到硬盘。
 if (PageDirty(page)) {
                        switch (pageout(page, mapping, sync_writeback)) {
                        case PAGE_SUCCESS:
                                if (PageWriteback(page) || PageDirty(page))
                                        goto keep;
                                /*
                                 * A synchronous write - probably a ramdisk.  Go
                                 * ahead and try to reclaim the page.
                                 */
                                if (!trylock_page(page))
                                        goto keep;
                                if (PageDirty(page) || PageWriteback(page))
                                        goto keep_locked;
                                mapping = page_mapping(page);
                        case PAGE_CLEAN:
                                ; /* try to free the page below */
                        }
}
//磁盘缓冲区: 如果页描述符所指向缓冲区不为空话,断开页描述与其关联。
 if (page_has_private(page)) {
                        if (!try_to_release_page(page, sc->gfp_mask))
                                goto activate_locked;
                        if (!mapping && page_count(page) == 1) {
                                unlock_page(page);
                                if (put_page_testzero(page))
                                        goto free_it;
                                else {
                                        /*
                                         * rare race with speculative reference.
                                         * the speculative reference will free
                                         * this page shortly, so we may
                                         * increment nr_reclaimed here (and
                                         * leave it off the LRU).
                                         */
                                        nr_reclaimed++;
                                        continue;
                                }
                        }
                }
//回收页高速缓冲和交换高速缓冲页面,实际从两者基树中删除
  if (!mapping || !__remove_mapping(mapping, page))
                        goto keep_locked;
                __clear_page_locked(page);

//收集要释放页面
free_it:
                nr_reclaimed++;
                if (!pagevec_add(&freed_pvec, page)) {
                        __pagevec_free(&freed_pvec);
                        pagevec_reinit(&freed_pvec);
                }
                continue;
        }
//集中释放收集的页面
        list_splice(&ret_pages, page_list);
        if (pagevec_count(&freed_pvec))
                __pagevec_free(&freed_pvec);
        count_vm_events(PGACTIVATE, pgactivate);
        trace_mm_pagereclaim_free(nr_reclaimed);
        return nr_reclaimed;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值