哪个网站做图找图片,移动网站 pc网站的区别吗,邢台建设企业网站费用,最简单网站设计的代码本文为旧的lru算法#xff0c;多代lru算法与旧算法的区别可稳步#xff1a;linux内存回收mglru算法-CSDN博客
1.shrink_node_memcgs
node_reclaim-__node_reclaim-shrink_node#xff0c;这里调用shrink_node_memcgs回收后#xff0c;要判断下是否分配内存速度比…
本文为旧的lru算法多代lru算法与旧算法的区别可稳步linux内存回收mglru算法-CSDN博客
1.shrink_node_memcgs
node_reclaim-__node_reclaim-shrink_node这里调用shrink_node_memcgs回收后要判断下是否分配内存速度比回收速度快太多这种情况可能会尝试停一段时间等回收完成reclaim_throttle然后再看是否需要继续回收should_continue_reclaim。实际入口shrink_node_memcgs如下
shrink_node_memcgs():
for each memory control group:/*** 按照指定的预留min/low内存从上层节点瓜分实际分到的min/low预留内存大小。* 具体见https://blog.csdn.net/qq_37517281/article/details/134466144*/mem_cgroup_calculate_protection()if (mem_cgroup_below_min(target_memcg, memcg)) {// 本group分配的未达到min预留内存尝试下个groupcontinue;} else if (mem_cgroup_below_low(target_memcg, memcg)) {// 如果指定不对未达到low限制的group回收内存则只标记下skipif (!sc-memcg_low_reclaim) {sc-memcg_low_skipped 1;continue;}}// 尝试回收页与slabshrink_lruvec();shrink_slab();/*** 计算些时回收压力: 回归页/扫描页数×100* 大于60是中等压力大于95是严重压力。*/vmpressure();
2.shrink_lruvec
shrink_lruvec 中会计算本次要扫描的页数然后触发实际的扫描和页回收shrink_list实现如下
shrink_lruvec():// 计算要扫描页数get_scan_count(lruvec, sc, nr);while 未扫描足够的页数且文件页或匿名页数量都不是for 2个 active lru list(file and anon)// 如果指定了may_deactivate则尝试将部分hot 页移至cold 链表中shrink_active_list();for 2个 inactive lru list(file and anon):shrink_inactive_list();// 如果匿名页的cold页少尝试deactivate 一些老的hot匿名页。shrink_active_list();
3.get_scan_count scan 四个lru链表页数计算方法如下get_scan_count
get_scan_count()/*** 先判断回收文件页还是匿名页只扫描文件页的情况* a.没有swap空间* b.一个cgroup的memory.swappness为0swapness表示对换出匿名页与重加载文件页的cost的加权,cost 指scan过程中发现的不可换出的页数换出页×32* c.指定了回收缓存文件页cache_trim_mode* 只扫描匿名页的情况* a.文件页很少* 同时回收文件页和匿名页的情况* a.即将oom时这时的priority为(后面扫描时对所有可扫描页的扫描比例为priority分之一)* 其它情况下会计算文件页与匿名页扫描比例比例的原始值控制在1/3 - 2/3之间* (当anon_cost为0时ap 与 fp 的未加权的原始比是1:2)* 取决于扫描时的costscan过程中发现的不可换出的页数换出页×32* 乘上一个换出匿名页与加载文件页的io cost比swapness/200**/total_cost sc-anon_cost sc-file_cost;anon_cost total_cost sc-anon_cost;file_cost total_cost sc-file_cost;total_cost anon_cost file_cost;ap swappiness * (total_cost 1);ap / anon_cost 1;fp (200 - swappiness) * (total_cost 1);fp / file_cost 1;fraction[0] ap;fraction[1] fp;denominator ap fp;// 计算 4 个 lru list (active/inactive × anon/file)扫描数量: if (!sc-memcg_low_reclaim low min) {protection low;sc-memcg_low_skipped 1;} else {protection min;}// scan lru页数-组内预留页数scan lruvec_size - lruvec_size * protection / (cgroup_size 1);// priority 默认为 12scan sc-priority;scan mem_cgroup_online(memcg) ?div64_u64(scan * fraction[file], denominator) :DIV64_U64_ROUND_UP(scan * fraction[file],denominator);
4.shrink_active_list
将active 页移至inactive页的方法shrink_active_list
shrink_active_list():/*** 处理一批本cpu上的页状态转换请求cpu_fbatches和对页标记可否回收的请求mlock_fbatch* 1、新访问的页和最新分配的页会记在fbatches-lru_add上处理函数是 lru_add_fn。* 、writeback的页放在lru_rotate.fbatch处理函数是 lru_move_tail_fn,将其放在inactive 的tail上等待回收页回收是从tail开始的* 、madvice 为dont need的页或是free了的设备页、文件页放在cpu_fbatches.lru_deactivate_file处理函数是 lru_deactivate_file_fn * 会将dirty/writeback/clean页放inactive的head上* 、匿名页比如内核自己使用并释放的页放在 cpu_fbatches.lru_deactivate处理函数是 lru_deactivate_fn 将页框放在 active 的head上* 、huge page 是lazyfree的放在cpu_fbatches.lru_lazyfree上处理函数是 lru_lazyfree_fn 会将页当成clean页放在inactive 的头上。*/lru_add_drain();// 从后向前扫描跳过高于指定zone的区和cma的区从这中间的区找可以unmap的页框或未map的页框isolate_lru_folios();for 每个扫描出的页框// 判断这个页框没有mlock的vma且它的mapping也没有标记unevictableif (unlikely(!folio_evictable(folio))) {folio_putback_lru(folio);continue;}// 如果buffer的总数太多且这个页框中有buffer则尝试解除映射if (unlikely(buffer_heads_over_limit)) {if (folio_test_private(folio) folio_trylock(folio)) {if (folio_test_private(folio))filemap_release_folio(folio, 0);folio_unlock(folio);}}// 尝试把code文件页加入active队列把其它页加入inactive队列list_add(folio-lru, l_inactive);// 给evictable的页引用减1引用不为0的加入到lru的inactive或active的lru中。引用为0则尝试释放对页框中有超过页的情况调用页框绑定的destroy对于只有一页的情况攒起来在后面两个函数内释放。move_folios_to_lru()// 释放只有一页的页框mem_cgroup_uncharge_list();free_unref_page_list();
5.shrink_inactive_list
shrink_inactive_list():// 处理一批本cpu上的页状态转换请求cpu_fbatches和对页标记可否回收的请求mlock_fbatchlru_add_drain();// 从lru中切出要扫描的页isolate_lru_folios();// 将一些页换出shrink_folio_list();// 将没有迁移成功、没有换出成功、没有写回文件的页重新加回原lru链表并将ref减move_folios_to_lru();// 统计costlru_note_cost(lruvec, file, stat.nr_pageout, nr_scanned - nr_reclaimed);// 将ref减后为的页框释放掉mem_cgroup_uncharge_list(folio_list);free_unref_page_list(folio_list);
6.shrink_folio_list
shrink_inactive_list会将部分页回收、送入swap区或迁移到其它numa node上。具体实现如下
shrink_folio_list():
if (folio_test_writeback(folio)) {/*** 如果已经标记了writeback和reclasim说明它在等io* 这时需要activate它并继续scan来找其它inactive list上可以回收的folio* 如果是swap区的将swapcache相关项清理掉*/if (current_is_kswapd() folio_test_reclaim(folio) test_bit(PGDAT_WRITEBACK, pgdat-flags)) {stat-nr_immediate nr_pages;goto activate_locked;} else if (writeback_throttling_sane(sc) ||!folio_test_reclaim(folio) ||!may_enter_fs(folio, sc-gfp_mask)) {/*** 如果本次扫描不没指定可访问文件系统__GFP_FS or __GFP_IO* 且这个页还没标记可回收就标记一下这个页框可回收并继续scan* 可能在下一次扫描时回收*/folio_set_reclaim(folio);stat-nr_writeback nr_pages;goto activate_locked;} else {/*** 如果已经标记了页框回收则已经扫描一遍了只能等writeback结束*/folio_unlock(folio);folio_wait_writeback(folio);/* then go back and try same folio again */list_add_tail(folio-lru, folio_list);continue;}
}
folio_check_references();
// 如果没有引用则考虑可否直接回收先尝试迁移到最近距离的下一个nodedemote_folio_list下一个node记录在全局的node_demotion中
if (do_demote_pass (thp_migration_supported() || !folio_test_large(folio))) {list_add(folio-lru, demote_folios);folio_unlock(folio);continue;
}
// 看是否是匿名可进swap区的页(有页面映射且没有人为它建过swapcache)为它建立swapcache项
if (folio_test_anon(folio) folio_test_swapbacked(folio)) {if (!folio_test_swapcache(folio)) {// 添加一个swap区的映射entryadd_to_swap();}
}
// 对于文件页和没有swapcache的匿名页需要给它解除页表映射项
if (folio_mapped(folio)) {try_to_unmap(folio, flags);
}
// 对于dirty的页只有kswapd进程可以直接回收其它进程只能柡注reclaim以防止stack overflow
if (folio_test_dirty(folio)) {// kswapd进程来回收了需要把tlb刷下去try_to_unmap_flush_dirty();pageout();
}
// 如果这个页框还有buffer尝试解除clean的和没有映射的buffer
if (folio_has_private(folio)) {filemap_release_folio(folio, sc-gfp_mask)
}