内存换出和缓冲区释放

与.11将普通内存和缓冲区分成不同的物理内存来处理不同,.4.0将这两者抽象成统一的内存管理接口 。而在阅读.4.0源码的过程中,发现内存的换出和缓冲区的释放在结构上似乎具有很强的相似性,具体体现在以下几点:
内存换出时,要考虑到内存是不是最近有被使用(LRULastUsed) 。而缓冲区也不会在进程释放完就马上释放,会停留在内存一段时间(因为从硬盘读数据到内存会影响到OS的效率),也需要通过LRU去将缓冲区释放内存换出是将暂时不用的内存写入到交换盘,待以后需要用到时通过换入到内存中;而缓冲区也需要将进程写入到内存的数据存储到硬盘中
1.Page 的LRU管理
关于page的LRU管理,有三个链表: 、、(与前两者全局的链表不同,这个在zone的管理结构中,因为这个已经向硬盘写入,但是没有回收而已) 。
Page一般在使用的时候是存在于;如果普通内存或者缓冲区因为长时间没使用(识别长时间没使用的方法--page老化),会将page从移至;在内存缺少的时候,当前进程或者一些周期性线程(例如)将page洗净(),将page从移至;最后线程会将page从中移除(之前能从hash表中查到,之后就再也查不到page的数据了),释放至buddy系统中,供其他的进程内存分配使用 。
2.Page的老化
Page的老化是LRU算法的基础,在.4.0中,函数会查看page是否有受到访问,如果受到了访问,;如果没有受到,就y 。直到page.age为0时,会ck,将page从移至 。
refill_inactive-->refill_inactive_scanrefill_inactive_scan{....//缓冲区的递增在这里做,普通内存的递增在swap_out(2.4.16将两者都抽象到Referenced)//但是递减,普通内存和缓冲区都在这做if (PageTestandClearReferenced(page)) {age_page_up_nolock(page);page_active = 1;} else {age_page_down_ageonly(page);....}
2.1普通内存的老化
查看普通内存是否受到访问,需要借助硬件机制 。在MMU中,将page映射到虚拟内存,每次通过虚拟地址访问,都会通过pgd-->pmd-->pte去访问page 。在MMU访问这些pgd/pmd/pte时,都会将置上,再通过young来检查page是否受到访问 。
会通过链表..next来遍历所有进程的结构体中的所有vma,从而确保遍历进程申请的所有虚拟地址,来检查page是否受到了访问,如下图 。
(注:这样遍历似乎在效率上存在很大的问题,例如vma申请了,但是没有映射内存;还比如说page被映射到了MMU中,但是因为效率的原因不允许被换出 。出现了这些情况,.4.0似乎还是一如既往的遍历了所有的vma 。所以后期似乎对这一块有所优化,将page映射的pte通过红黑树放在page的管理结构中,这样就可以通过page去查看pte是否被访问,或者将pte对应的page移至其他内存上,从而减少内存碎片,具体参考深入剖析Linux内核反向映射机制 to the World-CSDN博客)
refill_inactive-->swap_out-->swap_out_mm-->swap_out_vma-->swap_out_pgd-->swap_out_pmd-->try_to_swap_outtry_to_swap_out{... onlist = PageActive(page);/* Don't look at this pte if it's been accessed recently. *///普通内存受到访问age递增if (ptep_test_and_clear_young(page_table)) {age_page_up(page);goto out_failed;}//如果之前不再active_list中,refill_inactive_scan就不会将age递减 。所以需要在这里递减//据《linux内核源代码情景分析》第125页说:在do_swap_page的时候,page不会立即添加到active_list,而是在page_launder时在做,从看代码可知:如果是从hash中获取page,则会在active_list中,但是如果要从盘上读取,需要经过add_to_swap_cache,这里有可能将其添加到inactive_dirty_list 。if (!onlist)/* The page is still mapped, so it can't be freeable... */age_page_down_ageonly(page);...}