轉:http://www.wowotech.net/linux_kenrel/233.htmlhtml
做者:itrocker 發佈於:2015-11-12 20:37 分類:內存管理node
不管計算機上有多少內存都是不夠的,於是linux kernel須要回收一些不多使用的內存頁面來保證系統持續有內存使用。頁面回收的方式有頁回寫、頁交換和頁丟棄三種方式:若是一個不多使用的頁的後備存儲器是一個塊設備(例如文件映射),則能夠將內存直接同步到塊設備,騰出的頁面能夠被重用;若是頁面沒有後備存儲器,則能夠交換到特定swap分區,再次被訪問時再交換回內存;若是頁面的後備存儲器是一個文件,但文件內容在內存不能被修改(例如可執行文件),那麼在當前不須要的狀況下可直接丟棄。linux
1 回收的時機android
2 哪些內存能夠回收算法
2.1 頁框的回收緩存
LRU(Least Recently Used),近期最少使用鏈表,是按照近期的使用狀況排列的,最少使用的存在鏈表末尾,經過如下宏定義便可看出:函數
#define lru_to_page(_head) (list_entry((_head)->prev, struct page, lru)).net
每一個zone有5個LRU鏈表用以存放各類最近使用狀態的頁面。線程
enum lru_list {htm
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
};
其中INACTIVE_ANON、ACTIVE_ANON、INACTIVE_FILE、ACTIVE_FILE 4個鏈表中的頁面是能夠回收的。ANON表明匿名映射,沒有後備存儲器;FILE表明文件映射。
頁面回收時,會優先回收INACTIVE的頁面,只有當INACTIVE頁面不多時,纔會考慮回收ACTIVE頁面。
爲了評估頁的活動程度,kernel引入了PG_referend和PG_active兩個標誌位。爲何須要兩個位呢?假定只使用一個PG_active來標識頁是否活動,在頁被訪問時,設置該位,可是什麼時候清楚呢?爲此須要維護大量的內核定時器,這種方法註定是要失敗的。
使用兩個標誌,能夠實現一種更精巧的方法,其核心思想是:一個表示當前活動程度,一個表示最近是否被引用過,下圖說明了基本算法。
基本上有如下步驟:
(1)若是頁是活動的,設置PG_active位,並保存在ACTIVE LRU鏈表;反之在INACTIVE;
(2)每次訪問頁時,設置PG_referenced位,負責該工做的是mark_page_accessed函數;
(3)PG_referenced以及由逆向映射提供的信息用來肯定頁面活動程度,每次清除該位時,都會檢測頁面活動程度,page_referenced函數實現了該行爲;
(4)再次進入mark_page_accessed。若是發現PG_referenced已被置位,意味着page_referenced沒有執行檢查,於是對於mark_page_accessed的調用比page_referenced更頻繁,這意味着頁面常常被訪問。若是該頁位於INACTIVE鏈表,將其移動到ACTIVE,此外還會設置PG_active標誌位,清除PG_referenced;
(5)反向的轉移也是有可能的,在頁面活動程度減小時,可能連續調用兩次page_referenced而中間沒有mark_page_accessed。
若是對內存頁的訪問是穩定的,那麼對page_referenced和mark_page_accessed的調用在本質上是均衡的,於是頁面保持在當前LRU鏈表。這種方案同時確保了內存頁不會再ACTIVE與INACTIVE鏈表間快速跳躍。
2.2 slab緩存回收
slab緩存回收相對比較靈活,全部註冊到shrinker_list中的方法都會被執行。
內核默認針對每一個文件系統都註冊了prune_super方法,這個函數用來回收文件系統中再也不使用的dentry和inode緩存;
android的lowmemorykiller機制註冊了選擇性殺死進程的方法,回收進程使用的內存。
3怎樣回收頁框
其中shrink_page_list是真正回收頁面的過程
4週期性回收的頻率
4.1 kswapd
kswapd是內核爲每一個內存node建立的內存回收線程,爲何有了緊缺回收機制還須要週期性回收呢?由於有些內存分配是不容許阻塞等待回收的,好比中斷和異常處理程序中的內存分配;還有些內存分配不容許激活I/O訪問的。只有少數狀況的內存緊缺能夠完整執行回收過程,因此利用系統空閒時間回收內存很是必要。
該函數記錄了上一次均衡操做時所用的分配order,若是kswapd_max_order大於上一次的值,或者classzone_idx小於上一次的值,則調用balance_pgdat再次均衡該內存域,不然能夠進行短暫休眠,休眠的時間是HZ/10,對於arm(HZ=100)來講,休眠的時間就是1ms。
balance_pgdat均衡操做直到該內存域的zone_wartermark_ok爲止。
4.2 cache_reap
cache_reap用來回收slab中的空閒對象,若是空閒對象能夠還原成一個頁面,則釋放回buddy system。每次調用cache_reap會把全部的slab_caches遍歷一遍,以後休眠2*HZ,對於arm(HZ=100)來講,週期就是20ms。
5 參考文獻
(1)《understanding the linux kernel》
(2)《professional linux kernel architecture》