linux 記憶體管理---頁框回收(十)
- 為什麼需要頁回收?
- 觸發頁回收的時機
- 記憶體緊缺
- suspend-to-disk
- 週期性 (vmscan.c)
- 哪些頁可以被回收?
- 頁是如何被回收的?
- Reverse Mapping (Rmap.c)
static inline unsigned longvma_address(struct page *page, struct vm_area_struct *vma){ pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); unsigned long address; address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT); if (unlikely(address < vma->vm_start || address >= vma->vm_end)) { /* page should be within any vma from prio_tree_next */ BUG_ON(!PageAnon(page)); return -EFAULT; } return address;}通過頁描述符可以得到對應線性區的該頁的對應線性地址,通過線性地址就很容易得到頁表項了。static int try_to_unmap_anon(struct page *page){ struct anon_vma *anon_vma; struct vm_area_struct *vma; int ret = SWAP_AGAIN; anon_vma = page_lock_anon_vma(page); //page->mapping if (!anon_vma) return ret; list_for_each_entry(vma, &anon_vma->head, anon_vma_node) { //得到所有的線性區 ret = try_to_unmap_one(page, vma); if (ret == SWAP_FAIL || !page_mapped(page)) break; } spin_unlock(&anon_vma->lock); return ret;}2.檔案對映的頁逆向對映檔案對映頁描述符中的mapping欄位指向address_space資料結構它的思路也和匿名頁逆向對映相似,首先指出哪些線性區包含了給定頁,然後通過線性區找出對應的頁表項。但是和匿名對映不同的是,檔案對映的頁被共享的程序更多,比如標準c庫,幾乎被所有程序共享,所以包含給定頁的線性區連結串列就會很長,所以檔案對映的逆向對映採用了不同的實現方式:priority search trees, quickly locate all thememory regions that refer to the same page frame.每個檔案對應一個優先搜尋樹,它存放在address_space 物件的i_mmap 欄位中:struct address_space { struct inode *host; /* owner: inode, block_device */ struct radix_tree_root page_tree; /* radix tree of all pages */ ...
struct prio_tree_root i_mmap; /* tree of private and shared mappings */ ...
}prio_tree_node 資料結構表示的一個PST 節點,該資料結構在每個線性區描述符的shared.prio_tree_node欄位中。static int try_to_unmap_file(struct page *page){ struct address_space *mapping = page->mapping; pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); struct vm_area_struct *vma; struct prio_tree_iter iter; int ret = SWAP_AGAIN; unsigned long cursor; unsigned long max_nl_cursor = 0; unsigned long max_nl_size = 0; unsigned int mapcount; spin_lock(&mapping->i_mmap_lock); vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { //page->mapping->i_mmap存放搜尋樹的根,得到樹上的每個節點,然後container of()得到包含節點的線性區 ret = try_to_unmap_one(page, vma); if (ret == SWAP_FAIL || !page_mapped(page)) goto out; } ...
}
- 頁回收演算法
- 當按需裝入進程的一個匿名頁時,由do_anonymous_page ( )函數執行
- 當按需裝入記憶體對映檔案的一個頁時,由filemap_nopage ()函數執行
- 當按需裝入IPC 共享記憶體區的一個頁時, 由shme凡nopage () 函式執行
- 當從檔案讀取資料頁時,由do_generic_file_read () 函式執行
- 當換入一個頁時,由do_swap_page ( ) 函式執行
- 當在頁快取記憶體中搜索一個緩衝區頁時, __f ind_get_block {) 函式
當核心必須把一個頁標記為訪問過時, 就呼叫mark_page_accessed()函數。PFRA 掃描一頁呼叫一次page_referenced()函式,如果PG_referenced標誌或頁表項中的某些Accessed標誌位置位.則該函式返回1,否則返回0。該函式首先檢查頁描述符的PG_referenced標誌。如果標誌置位則清0。從活動連結串列到非活動連結串列移動頁不是由page_referenced()函式,而是由refill_inactive_zone()函式實施的。refill_inactive_zone()函式由shrink_zone()呼叫.而shrink_zone ()函式對頁快取記憶體和使用者態地址空間進行頁回收,refill_inactive_zone()函式的工作至關重要,因為,從活動連結串列將頁移到非活動鏈表就意味著頁遲早要被PFRA 捕獲。如果函式的掠奪性過強,就會有過多的頁從活動鏈表被移動到非活動連結串列.因此, PFRA 就會回收大量的頁框,系統性能會受到影響.反過來,如果函式太懶惰, 就沒有足夠的採用頁來補充非活動連結串列, PFRA 就不能回收內存。為此,該函式可以調整自己的行為:開始時.對每次呼叫,掃描非活動連結串列中少量的頁,但是當PFRA 很難回收記憶體時,refill_inactive_zone()在每次呼叫時就逐漸增加掃描的活動頁數, scan_control 資料結構中priority字段的值控制該函式的行為(低值表示更緊迫的優先順序)。LRU 連結串列中有兩類頁:屬於使用者態地址空間的頁、不屬於任何使用者態程序且在頁快取記憶體中的頁.PFRA 傾向於壓縮頁高速快取,而將使用者態程序的頁留在RAM 中.然而,每一種策略中都沒有一個固定的黃金法則保證在每個場景中系統的高效能,所以refill_inactive_zone()函式使用交換傾向( swap tendency ) 經驗值,由它確定函式是移動所有的頁還是隻移動不屬於使用者態地址空間的頁。函式按如下公式計算交換傾向值: 交換傾向值=對映比率/2 +負荷值+交換值對映比率( mapped ratio ) 是使用者態地址空間所有記憶體管理區的頁(sc->nr_mapped)佔所有可分配頁框數的百分比。mapped_ratio 的值大表示動態記憶體大部分用於使用者態進程.而值小則表示大部分用於頁快取記憶體. mapped_ratio = (sc->nr_mapped * 100) / total_memory;負荷值( distress ) 用於表示PFRA 在管理區中回收頁框的效率, 其依據是前一次PFRA執行時管理區的掃描優先順序,這個優先順序存放在管理區描述符的prev_priority 欄位 distress = 100 >> zone->prev_priority;
最後,交換值( swappiness ) 是一個使用者定義常數.預設值為60. 系統管理員可以在/proc/sys/vm/swappiness 檔案內修改這個值,或用相應的sysctl ()系統呼叫調整這個值。只有當管理區交換傾向值大於等於1 00 時.頁才從程序地址空間回收.那麼當系統管理員將交換值設為0 時, PFRA 就不會從使用者態地址空間回收頁,除非管理區的前一次優先級為0 (這不大可能發生).如果系統管理員將交換值設為1 00 ,那麼PFRA 每次呼叫該函式時都會從使用者態地址空間回收頁.if (swap_tendency >= 100) reclaim_mapped = 1; while (!list_empty(&l_hold)) { cond_resched(); page = lru_to_page(&l_hold); list_del(&page->lru); if (page_mapped(page)) { if (!reclaim_mapped || (total_swap_pages == 0 && PageAnon(page)) || page_referenced(page, 0, sc->priority <= 0)) { list_add(&page->lru, &l_active); continue; } } list_add(&page->lru, &l_inactive); }從try_to_free_pages() 到shrink_cache( ),這些函式目的是找到要回收的頁,shrink_list() 函式才是真正執行頁回收,將page list放入夥伴系統中。shrink_slab()函式用於釋放obj cache到slab分配器中,比如dentry cache, inode cachecache_reap()函式用於釋放slab分配器中空閒的slab,即歸還slab佔據的頁到夥伴系統中
- OOM(out of memory)
- Swapping
換出頁識別符號可以很簡單地而又唯一地標識一個換出頁.這是通過在swap_info陣列中指定交換區的索引和在交換區內指定頁槽的索引實現的.換出頁識別符號的格式如下:
swp_entry ( type,offfset)巨集負責從交換區索引type 和頁槽索引offset中構造換出頁識別符號。swp_type和swp_offset 巨集正好相反,它們分別從換出頁識別符號中提取出交換區索引和頁槽索引.當頁被換出時,其識別符號就作為頁的表項插入頁表中,這樣在需要時就可以再找到這個頁。要注意這種識別符號的最低位與Present 標誌對應,通常被清除來說明該頁目前不在RAM 中。啟用和禁用交換區一旦交換區被初始化,超級使用者(或者更確切地說是任何具有CAP_ SYS_ADM
相關推薦
linux 記憶體管理---頁框回收(十)
為什麼需要頁回收?linux的設計哲學之一:儘可能多的使用記憶體,比如儘可能的多使用memory cache,disk cache,因為這在系統負載比較小時,能夠提升系統性能,但是隨著cache越來越多
深入淺出記憶體管理--頁描述符(Page)
核心中採用struct page來描述實體記憶體頁,它的主要成員如下(非全部成員): unsigned long flags; 標誌位,核心中每個page的狀態可以由此標誌位來表示,列舉幾個標誌位: PG_locked 頁被鎖定,比如在磁碟I/O操作中涉及到的頁,不
Linux記憶體管理之slab機制(概述)
通過前面所有程式碼的分析和總結,已經把各個部分熟悉了一遍,在此對Linux核心中slab機制做最後的總結。 夥伴系統演算法採用頁作為基本記憶體區,這適合於大塊記憶體的請求。對於小記憶體區的申請,比如說幾十或幾百個位元組,我們用slab機制。 Slab分配器把物件分組放進快取
Linux內核線程kernel thread詳解--Linux進程的管理與調度(十)
block 完成 lag 工作原理 並行 kernel png 定義 define 內核線程 為什麽需要內核線程 Linux內核可以看作一個服務進程(管理軟硬件資源,響應用戶進程的種種合理以及不合理的請求)。 內核需要多個執行流並行,為了防止可能的阻塞,支持多線程是必要的。
Linux記憶體管理之slab機制(初始化)
一、核心啟動早期初始化 start_kernel()->mm_init()->kmem_cache_init() 執行流程: 1,初始化靜態initkmem_list3三鏈; 2,初始化cache_cache的nodelists欄位為1中的三鏈; 3,根據記憶
Linux記憶體管理之slab機制(釋放物件)
Linux核心中將物件釋放到slab中上層所用函式為kfree()或kmem_cache_free()。兩個函式都會呼叫__cache_free()函式。 程式碼執行流程: 1,當本地CPU cache中空閒物件數小於規定上限時,只需將物件放入本地CPU cache中;
linux程序管理之輕量級程序(四)
在Linux中,輕量級程序可以是程序,也可以是執行緒。我們所說的執行緒,在Linux中,其實是輕量級程序之間共享程式碼段,檔案描述符,訊號處理,全域性變數時; 如果不共享,就是我們所說的程序。 程序是資源管理的最小單位,執行緒是程式執行的最小單位。在作業系統設計上,從程序演化出執行緒,最主要的目的就是減小
linux程序管理之程序建立(三)
在linux系統中,許多程序在誕生之初都與其父程序共同用一個儲存空間。但是子程序又可以建立自己的儲存空間,並與父程序“分道揚鑣”,成為與父程序一樣真正意義上的程序。 linux系統執行的第一個程序是在初始化階段“捏造出來的”。而此後的執行緒或程序都是由一個已存在的程序像細胞分裂一樣通過系統呼叫複
Linux電源管理_autosleep--(五)【轉】
本文轉載自:https://blog.csdn.net/wlsfling/article/details/46005409 1. 前言 Autosleep也是從Android wakelocks補丁集中演化而來的(Linux電源管理(9)_wakelocks),用於取代Android wakelocks中
Linux學習筆記CentOS 6.5(十)---Mysql防火牆開放3306埠
防火牆開放3306埠 1、開啟防火牆配置檔案 vi /etc/sysconfig/iptables 2、增加下面一行 -A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT
Python 下字串的連線、簡單替換與unicode字串- 千月的python linux 系統管理指南學習筆記(12)
Python 下字串的連線、簡單替換與unicode字串 繼續上一章的內容,看一看字串的連線和替換 字串的連線 join() 將多個字串連線起來的”膠水“ 字元物件.join(字串或者列表) #連線字串,或者與列表裡的字元分別連線。 光是將2個字串相連。其實意義不大,一個
Linux核心--網路棧實現分析(十)--網路層之IP協議(下)
本文分析基於Linux Kernel 1.2.13作者:閆明注:標題中的”(上)“,”(下)“表示分析過程基於資料包的傳遞方向:”(上)“表示分析是從底層向上分析、”(下)“表示分析是從上向下分析。上篇博文分析傳輸層最終會呼叫函式ip_queue_xmit()函式,將傳送資料
Python 下字串的提取、分割與刪除- 千月的python linux 系統管理指南學習筆記(11)
Python 下字串的提取、分割與刪除 對於文字來講,提取、分割和刪除是我們用的較多的操作。 文字我們可以看成是字串物件。首先說到的是 in 和 not in操作。 字串的提取 in 和 not i
linux 記憶體定址 學習筆記(一)
ARM:RISC,精簡指令系統集 X86:CISC,複雜指令系統集 CISC:犧牲處理器本身的複雜度,換取高效能 RISC:將複雜度交給了編譯器,犧牲了程式大小和指令頻寬,換取了簡單和低功耗的硬體實現 CPL:current privilege leve
嵌入式Linux C程式設計學習之路(十)——標準IO fopen/fclose
標準IO與檔案IO的對應函式 檔案IO: 標準IO open fopen close
Linux使用者管理全攻略(二)
摘要:本文詳解使用者(User)和使用者組(Group)的配置檔案,本文是《Linux 使用者(User)和使用者組(Group)管理概述》文件的關健部份的細化;通過本文,您至少能明白/etc/passwd /etc/group ,以及什麼是UID和GID 等;其中對UID的
Python 建立、讀取和寫入檔案以及yield關鍵字- 千月的python linux 系統管理指南學習筆記(14)
無論是日誌檔案還是配置檔案都是我們日常運維中常見的型別,學習處理檔案的關鍵是學會如何處理文字資料。Python 包含一個稱為 file 的內建型別,可以用來處理檔案。 建立檔案物件 為了讀取一個現有的檔案,我們需要建立一個新的檔案物件,以用來對檔案進行互動。 open
[Linux記憶體]slab分配器學習筆記(一)--概念
http://blog.csdn.net/vanbreaker/article/details/76642961,為什麼需要slab分配器: 利用夥伴系統進行分配記憶體只能按照頁的單位進行分配,這樣會造成很多的記憶體浪費,多了很多記憶體碎片,比如只需要申請10位元組的,結
abp(net core)+easyui+efcore實現倉儲管理系統——多語言(十)
abp(net core)+easyui+efcore實現倉儲管理系統目錄 abp(net core)+easyui+efcore實現倉儲管理系統——ABP總體介紹(一) abp(net core)+easyui+efcore實現倉儲管理系統——解決方案介紹
【原創】(十一)Linux記憶體管理slub分配器
背景 Read the fucking source code! --By 魯迅 A picture is worth a thousand words. --By 高爾基 說明: Kernel版本:4.14 ARM64處理器,Contex-A53,雙核 使用工具:Source Insight 3.5,