Linux Kernel elemantary Knowledge

入門(mén)寫(xiě)的材料,湊一篇o(╥﹏╥)o... 偏簡(jiǎn)單,偏內(nèi)存

什么是匿名頁(yè)和文件頁(yè)?

匿名頁(yè)

? ? ? ? 匿名頁(yè),沒(méi)有文件背景的頁(yè)面,如stack,heap,數(shù)據(jù)段等;他們沒(méi)有對(duì)應(yīng)的硬盤(pán)文件,因此如果要交換,只能交換到虛擬內(nèi)存 zram或者Linux的swap硬盤(pán)分區(qū),此部分頁(yè)面,如果系統(tǒng)內(nèi)存不充分,可以被swap到swapfile或者硬盤(pán)的swap分區(qū)。

(安卓手機(jī)上是默認(rèn)swappiness是60,不過(guò)為了減少文件頁(yè)回收,都會(huì)選擇上調(diào),更多選擇壓入ZRAM)

文件頁(yè)

? ? ? ? 有文件背景的頁(yè)面,比如代碼段、比如read/write方法讀寫(xiě)的文件、比如mmap讀寫(xiě)的文件;他們有對(duì)應(yīng)的硬盤(pán)文件,因此如果要交換,可以直接和硬盤(pán)對(duì)應(yīng)的文件進(jìn)行交換。內(nèi)存緊張時(shí),非dirty的文件頁(yè)可以直接drop掉,所以這個(gè)也算作MemAvailable中。

cache包含文件頁(yè)(active和inactive)? zram_swap中存的是匿名頁(yè)

什么是內(nèi)存碎片?

? ? ? ? ? ? 造成堆利用率很低的主要原因是就是內(nèi)存碎片。當(dāng)雖然有未使用的內(nèi)存但不能用來(lái)滿足分配請(qǐng)求時(shí),就會(huì)發(fā)生該現(xiàn)象。有兩種形式的碎片:內(nèi)部碎片(internal fragmentation)和外部碎片(external fragmentation)。

外部碎片(主要問(wèn)題)

? ? ? ? 當(dāng)空閑內(nèi)存合計(jì)起來(lái)足夠滿足一個(gè)分配請(qǐng)求,但是沒(méi)有一個(gè)單獨(dú)的空閑塊足夠大可以來(lái)處理這個(gè)請(qǐng)求。

網(wǎng)上搜了個(gè)比喻,挺好理解:

? ? ? ? 我們將信息比作貨物,將存儲(chǔ)空間比作倉(cāng)庫(kù)來(lái)舉例子。假設(shè),我們有編號(hào)為1、2、3、4、5、6的6間倉(cāng)庫(kù)庫(kù)房,前天送來(lái)了一大宗貨,依次裝入了1、2、3、4、5號(hào)倉(cāng)庫(kù),昨天又因故將4號(hào)庫(kù)房的貨物運(yùn)走了,那么數(shù)值上說(shuō)我們還有兩間空倉(cāng)庫(kù)的空間,但是如果這時(shí)候送來(lái)兩間倉(cāng)庫(kù)容量的貨物但要求必須連續(xù)存放的話,我們實(shí)際上是裝不下的。這時(shí)的4、6號(hào)倉(cāng)庫(kù),就成為一種空間的碎片。由于這樣的原因形成的空間碎片,我們稱之為外部碎片。從上面的例子我們可以理解,外部碎片是可以通過(guò)一些措施來(lái)改善或者解決的。對(duì)于在硬盤(pán)上的外部碎片,我們通常用磁盤(pán)碎片整理來(lái)解決,對(duì)應(yīng)上面的例子,就是將5號(hào)倉(cāng)庫(kù)的貨物及時(shí)移動(dòng)到新騰出的4號(hào)倉(cāng)庫(kù),這樣,1-4號(hào)倉(cāng)庫(kù)都是滿的,而5、6號(hào)倉(cāng)庫(kù)則形成了有效的、連續(xù)的空間,能夠適應(yīng)新的應(yīng)用要求了;對(duì)于內(nèi)存中的外部碎片,我們內(nèi)存管理中常用的頁(yè)面管理形式,就是為了解決這個(gè)問(wèn)題的。


內(nèi)部碎片(這個(gè)很少了)

? ? ? ? 當(dāng)一個(gè)進(jìn)程裝入到固定大小的分區(qū)塊(比如頁(yè))時(shí),假如進(jìn)程所需空間小于分區(qū)塊,則分區(qū)塊的剩余的空間將無(wú)法被系統(tǒng)使用

? ? ? ? 還是沿用上面的例子,這次我們的6間倉(cāng)庫(kù)目前都是空置的,但是假設(shè)我們管理倉(cāng)庫(kù)的最小空間單位是間,今天運(yùn)來(lái)了容量為2.5間倉(cāng)庫(kù)的貨物,那也要占用我們1-3號(hào)3間倉(cāng)庫(kù),盡管3號(hào)倉(cāng)庫(kù)還閑置著一半的空間,但是這半間倉(cāng)庫(kù)已經(jīng)不能再利用了(因?yàn)槭且蚤g為最小單位么);這時(shí),我們的倉(cāng)庫(kù)中就形成了半間倉(cāng)庫(kù)的空間碎片,我們稱之為內(nèi)部碎片。倉(cāng)庫(kù)的有效容量只剩下3間倉(cāng)庫(kù)了。

內(nèi)存分配原理及大體流程

內(nèi)存分配原理

? ? ? ? 在NUMA模型中,每個(gè)CPU都有自己的本地內(nèi)存節(jié)點(diǎn)(memory node),而且還可以通過(guò)QPI總線訪問(wèn)其他CPU下掛的內(nèi)存節(jié)點(diǎn),訪問(wèn)本地內(nèi)存要比訪問(wèn)其他CPU下的內(nèi)存的快約30%。Android只有一個(gè)Node 0,這個(gè)就比較簡(jiǎn)單了。

? ? ? ? Linux中對(duì)所有的內(nèi)存進(jìn)行統(tǒng)一管理,但由于關(guān)聯(lián)不同的CPU導(dǎo)致訪問(wèn)速度不同,因此又將內(nèi)存劃分為節(jié)點(diǎn)(node);在節(jié)點(diǎn)內(nèi)部,又進(jìn)一步細(xì)分為內(nèi)存域(zone),比如DMA_ZONE,Normal_ZONE,還有虛擬Movable_ZONE

ps: 提一下movable zone,就是設(shè)計(jì)用來(lái)防止碎片化,把Highmem和movable分配需求集中放到這個(gè)zone中,使得這個(gè)zone中都是可移動(dòng)頁(yè)面,方便頁(yè)面規(guī)整。但是實(shí)際項(xiàng)目中這個(gè)zone基本都是空的


針對(duì)不同的用途,Linux內(nèi)核將所有的物理頁(yè)面劃分到3類(lèi)內(nèi)存管理區(qū)域中:

ZONE_DMA:? ? 該區(qū)域物理頁(yè)面專供I/O設(shè)備的DMA使用,需要連續(xù)的緩沖區(qū),不經(jīng)過(guò)MMU使用物理地址訪問(wèn)內(nèi)存。

ZONE_NORMAL:內(nèi)核直接映射使用,一般存放kernal、mem_map數(shù)組等常用數(shù)據(jù)。

ZONE_HIGHMEM:高端內(nèi)存,內(nèi)核無(wú)法直接使用,存放用戶數(shù)據(jù)、頁(yè)表等不常用數(shù)據(jù)。安卓無(wú)

內(nèi)核根據(jù)價(jià)值(HIGHMEM內(nèi)存無(wú)依賴最廉價(jià),DMA最昂貴數(shù)量少易用盡)為內(nèi)存域定義了優(yōu)先級(jí),從高到低為:ZONE_HIGHMEM > ZONE_NORMAL > ZONE_DMA。優(yōu)先選擇距離較近的node,再選擇優(yōu)先級(jí)較高的zone。

? ? ? 如果從某個(gè)zone申請(qǐng)內(nèi)存失敗,就使用node_zonelists,它定義了一個(gè)zone搜索列表(每一項(xiàng)代表一個(gè)zone),當(dāng)從某個(gè)node的某個(gè)zone申請(qǐng)內(nèi)存失敗后,會(huì)搜索該列表,查找一個(gè)合適的zone繼續(xù)分配內(nèi)存。


? ? ? 每個(gè)zone都有自己的伙伴系統(tǒng)(buddy system)?;锇橄到y(tǒng)是基于內(nèi)存塊的內(nèi)存管理策略,它將物理內(nèi)存分成許多大小為2^n個(gè)page的內(nèi)存塊(其中n=0,1,2.....10,即最大內(nèi)存塊為4M),相同大小的內(nèi)存塊被鏈入同一個(gè)鏈表中。管理區(qū)描述符(struct zone)中,struct free_area用于描述伙伴系統(tǒng)。

? ? ? 假設(shè)要分配一個(gè)n=3即2^3=8個(gè)page的內(nèi)存塊,算法首先搜索free_area[3]指定的鏈表,檢查是否有空閑的內(nèi)存塊。如果有,直接從鏈表上摘取一個(gè)內(nèi)存塊;如果沒(méi)有,算法會(huì)檢查更大內(nèi)存塊的鏈表,即free_area[4]指定的鏈表,如果該鏈表有空閑塊,則摘取一個(gè)空閑塊并分割為大小相同的兩部分(伙伴),一部分返回給內(nèi)存申請(qǐng)者,另一部分加入到free_area[3]指定的鏈表中。如果free_area[4]指定的鏈表中也沒(méi)有空閑塊,則繼續(xù)搜索更大的內(nèi)存塊鏈表,直至free_area[10]。

在分配頁(yè)框的方式有兩種:快速分配和慢速分配:

快速分配:會(huì)根據(jù)zonelist鏈表的優(yōu)先級(jí)順序,以zone的low閥值從相應(yīng)zone的 伙伴系統(tǒng)中分配連續(xù)頁(yè)框。

慢速分配:在快速分配失敗之后執(zhí)行,會(huì)根據(jù)zonelist鏈表的優(yōu)先級(jí)順序,以zone 的min閥值從相應(yīng)zone的伙伴系統(tǒng)中分配連續(xù)頁(yè)框。如果失敗,會(huì)喚醒kswapd 內(nèi)核線程,進(jìn)行異步壓縮、直接內(nèi)存回收、oom以及輕同步壓縮,進(jìn)行內(nèi)存回收,在這些內(nèi)存回收操作的過(guò)程當(dāng)中,幾乎每一步會(huì)進(jìn)行快速分配嘗試獲取內(nèi)存,快速滿足內(nèi)存分配請(qǐng)求才是第一位。

內(nèi)存分配流程


內(nèi)存分配入口:alloc_pages(gfp_t gfp_mask, unsigned int order)

調(diào)用函數(shù)struct page *alloc_pages_current(gfp_t gfp, unsigned order)

再往下調(diào)用核心函數(shù)__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, int preferred_nid,nodemask_t *nodemask)

看下核心方法的具體流程: //參考kernel-4.19代碼

1、先開(kāi)始快速分配,調(diào)用get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags,const struct alloc_context *ac) ac上下文包含里面的zonelist,遍歷掃描zonelist,根據(jù)每個(gè)zone的水線watermark,zone_watermark_ok()查找到足夠空閑的zone,在try_this_zone中查找可使用的頁(yè)面返回,完成分配。在一些急迫的事務(wù)中,可以指定ALLOC_NO_WATERMARKS,這樣會(huì)不會(huì)對(duì)水位進(jìn)行驗(yàn)證。

2、 快速分配失敗時(shí),調(diào)用慢速分配方法__alloc_pages_slowpath(gfp_t gfp_mask,unsigned int order,struct? alloc_context *ac)。

3、慢速分配先進(jìn)入retry_cpuset:首先調(diào)用wake_all_kswapds(order,ac),喚醒所有kswapd守護(hù)進(jìn)程進(jìn)行物理頁(yè)面的回收(一般1-2個(gè),linux可以設(shè)置為2個(gè),Android考慮到功耗,一般只能設(shè)置為1個(gè))。

4、再次調(diào)用get_page_from_freelist()進(jìn)行快速分配。

5、還是分不出頁(yè)面就調(diào)用__alloc_pages_direct_compact(gfp _mask, order,alloc_flags, ac,INIT_COMPACT_PRIORITY,&compact_result);在函數(shù)中繼續(xù)調(diào)用 try_to_compact_pages(),繼續(xù)調(diào)用for_each_zone_zonelist_nodemask()對(duì)zonelist中的每個(gè)zone進(jìn)行內(nèi)存壓縮。在__alloc_pages_direct_compact()中再次調(diào)用get_page_from_freelist(),如果成功,函數(shù)返回page。

6、還是失敗的話進(jìn)入retry過(guò)程:首先喚醒所有回收線程,確保不會(huì)意外睡去。

7、嘗試進(jìn)行g(shù)et_page_from_freelist()。

8、做一些校驗(yàn),如果不能回收(reclaim),就返回nopage。

9、調(diào)用回收方法__alloc_pages_direct_reclaim(gfp_mask, order, alloc_flags, ac,&did_some_progress)成功就返回page。

10、不成功就調(diào)用__alloc_pages_direct_compact()壓縮內(nèi)存,成功就返回page

11、參數(shù)判定決定是否重新從retry或者retry_cpuset開(kāi)始執(zhí)行。

12、到這步還是無(wú)法找到空閑頁(yè)面,準(zhǔn)備oom殺進(jìn)程,調(diào)用方法__alloc_pages_may_oom(gfp_mask, order, ac, &did_some_progress)。

13、只要oom循環(huán)就一直進(jìn)行retry直到找到空閑頁(yè)面,進(jìn)程結(jié)束就返回null。

內(nèi)存回收原理及大體流程

內(nèi)存回收原理

頁(yè)面回收的方式(沒(méi)有ZRAM,ZRAM的匿名頁(yè)壓縮放入ZRAM區(qū)域)

? ? 1、頁(yè)回寫(xiě) 存在臟頁(yè),即文件頁(yè)在內(nèi)存中有改動(dòng),將內(nèi)存同步到設(shè)備

? ? 2、頁(yè)交換 匿名頁(yè),交換到swap分區(qū),再次訪問(wèn)時(shí)換回內(nèi)存

? ? 3、頁(yè)丟棄 文件頁(yè)沒(méi)有改動(dòng),或者不能修改,可直接丟棄

頁(yè)面回收的時(shí)機(jī)

wartermark:水線,分為【W(wǎng)MARK_HIGH】、【W(wǎng)MARK_LOW】、【W(wǎng)MARK_MIN】。內(nèi)核線程kswapd檢測(cè)到不同的水線值會(huì)進(jìn)行不同的處理,當(dāng)空閑page數(shù)大于high時(shí),不需要進(jìn)行內(nèi)存回收;當(dāng)空閑page數(shù)低于low時(shí),開(kāi)始進(jìn)行內(nèi)存回收,將page換出到硬盤(pán);當(dāng)空閑page數(shù)低于min時(shí),表示內(nèi)存回收的壓力很重,可用page數(shù)已經(jīng)很少了,必須加快進(jìn)行內(nèi)存回收。

WMARK_MIN= min_free(單位為page),假設(shè)為min_free。(因?yàn)槭敲總€(gè)zone各有一套watermark參數(shù),實(shí)際計(jì)算效果是根據(jù)各個(gè)zone大小所占內(nèi)存總大小的比例,而算出來(lái)的每個(gè)zone的min_free)

WMARK_LOW = WMARK_MIN * 5 / 4 + extra_free_kbytes

WMARK_HIGH = WMARK_MIN * 3 / 2

LRU(Least Recently Used),近期最少使用鏈表,按照近期的使用情況排列,最少使用的存在鏈表末尾。每個(gè)zone有5個(gè)LRU鏈表:

? ? ? ? LRU_INACTIVE_ANON 非活動(dòng)匿名頁(yè)lru鏈表,PG_active=0

? ? ? ? LRU_ACTIVE_ANON 活動(dòng)匿名頁(yè)lru鏈表,PG_active=1

? ? ? ? LRU_INACTIVE_FILE? 非活動(dòng)文件頁(yè)lru鏈表,PG_active=0

? ? ? ? LRU_ACTIVE_FILE 活動(dòng)文件頁(yè)lru鏈表,PG_active=0

? ? ? ? LRU_UNEVICTABLE zone中所有禁止換出的頁(yè)

頁(yè)面回收時(shí),優(yōu)先回收INACTIVE的頁(yè)面。

? ? ? ? 當(dāng)內(nèi)存塊被釋放時(shí),算法首先會(huì)檢查它的伙伴是否存在,如果不存在,直接將內(nèi)存塊加入到對(duì)應(yīng)的鏈表中;如果存在,將兩個(gè)伙伴合并為一個(gè)更大的內(nèi)存塊,并繼續(xù)檢查該內(nèi)存塊的伙伴是否存在,如果存在,繼續(xù)向上合并,否則鏈入相應(yīng)的鏈表。

? ? ? ? slab緩存回收相對(duì)比較靈活,所有注冊(cè)到shrinker_list中的方法都會(huì)被執(zhí)行。內(nèi)核默認(rèn)針對(duì)每個(gè)文件系統(tǒng)都注冊(cè)了prune_super方法,這個(gè)函數(shù)用來(lái)回收文件系統(tǒng)中不再使用的dentry和inode緩存;android的lowmemorykiller機(jī)制注冊(cè)了選擇性殺死進(jìn)程的方法,回收進(jìn)程使用的內(nèi)存。

頁(yè)面回收具體流程見(jiàn)shrink_zone()。

內(nèi)存回收流程

? ? ? ? shink_zone()可以將某些頁(yè)面從active鏈表移到inactive鏈表,由shrink_active_list()實(shí)現(xiàn)的。接著從inactive鏈表中選定一定數(shù)目的頁(yè)面,將其放到一個(gè)臨時(shí)鏈表中,這由函數(shù)shrink_inactive_list()完成。該函數(shù)最終會(huì)調(diào)用shrink_page_list()去回收這些頁(yè)面。函數(shù)shrink_page_list()返回的是回收成功的頁(yè)面數(shù)目。函數(shù)shrink_slab()會(huì)遍歷shrinker鏈表,從而對(duì)所有注冊(cè)了shrinker函數(shù)的磁盤(pán)緩存進(jìn)行處理。

shrink_zone()函數(shù)的流程:

先從root_memcg開(kāi)始遍歷memcg:

? ? ? ? 1、獲取memcg的lru鏈表描述符lruvec

? ? ? ? 2、獲取memcg的swapiness(會(huì)影響掃描頁(yè)框的數(shù)量)

? ? ? ? 3、調(diào)用shrink_lruvec()對(duì)此memcg的lru鏈表進(jìn)行處理

shrink_lruvec()函數(shù)處理文件頁(yè)和匿名頁(yè)lru鏈表的流程為:

1. 調(diào)用get_scan_count()計(jì)算每個(gè)lru鏈表需要掃描的頁(yè)框數(shù)量,保存到nr數(shù)組中

2. 循環(huán)判斷nr數(shù)組中是否還有l(wèi)ru鏈表沒(méi)有掃描完成

? ? ? ? 以活動(dòng)匿名頁(yè)lru鏈表、非活動(dòng)匿名頁(yè)lru鏈表、活動(dòng)文件頁(yè)lru鏈表、非活動(dòng)文件頁(yè)lru鏈表的順序作為一輪掃描,每次每個(gè)lru鏈表掃描32個(gè)頁(yè)框,并且在nr數(shù)組中減去lru鏈表對(duì)應(yīng)掃描的數(shù)量,掃描過(guò)程中,調(diào)用shrink_list()

? ? ? 一輪掃描結(jié)束后判斷是否回收到了足夠頁(yè)框,沒(méi)有回收到足夠頁(yè)框則跳到 2 繼續(xù)循環(huán)判斷nr數(shù)組

? ? ? ? 已經(jīng)回收到了足夠頁(yè)框,當(dāng)nr數(shù)組有剩余時(shí),判斷是否要對(duì)lru鏈表繼續(xù)掃描,如果要繼續(xù)掃描,則跳到2

3. 如果非活動(dòng)匿名頁(yè)lru鏈表中頁(yè)數(shù)量太少,則對(duì)活動(dòng)匿名頁(yè)進(jìn)行一個(gè)32個(gè)頁(yè)框的掃描

4. 如果太多臟頁(yè)正在進(jìn)行回寫(xiě),則睡眠

shrink_list()在處理過(guò)程如下:

先判斷是否為活動(dòng)lru鏈表,如果是,判斷非活動(dòng)lru鏈表的頁(yè)數(shù)是否過(guò)少,過(guò)少就調(diào)用shrink_active_list(),否則調(diào)用shrink_inactive_list()處理非活動(dòng)鏈表:

活動(dòng)lru鏈表處理流程:

1、將本地cpu的lru緩存全部清空,將lru緩存的頁(yè)放到lru鏈表中,而其他CPU的則不處理

2、根據(jù)sc->may_writepage與sc->may_unmap從鏈表尾部選擇要隔離的頁(yè)

3、如果結(jié)點(diǎn)buffer_heads數(shù)量超過(guò)限制值,則會(huì)嘗試對(duì)掃描到的文件頁(yè)進(jìn)行buffer_heads的釋放,進(jìn)行釋放后的文件頁(yè)的page->_count--

4、將所有映射了隔離頁(yè)的頁(yè)表項(xiàng)Accessed都清0

5、將最近被訪問(wèn)過(guò)的代碼段的頁(yè)移動(dòng)到活動(dòng)lru鏈表頭部,其余頁(yè)都移動(dòng)到非活動(dòng)lru鏈表頭

6、將page->_count = 0的頁(yè)進(jìn)行釋放

? ? ? ? 非活動(dòng)lru鏈表處理流程與shrink_inactive_list()函數(shù)流程差不多,首先要求當(dāng)前CPU的所有l(wèi)ru緩存將頁(yè)放入到lru鏈表中,然后通過(guò)isolate_lru_pages()函數(shù)從活動(dòng)lru鏈表末尾掃描出符合要求的頁(yè),這些頁(yè)會(huì)通過(guò)page->lru加入到page_list鏈表中,然后調(diào)用shrink_page_list()對(duì)這個(gè)page_list鏈表中的頁(yè)進(jìn)行回收處理,之后將page_list鏈表中剩余的頁(yè)放回到它們應(yīng)該放入到鏈表中。


shrink_page_list()主要邏輯:

1、如果頁(yè)面被鎖住了,放入繼續(xù)將頁(yè)面保留在inactive list中,后就再掃描到底時(shí)候再試圖回收這些page

2、如果回寫(xiě)控制結(jié)構(gòu)體標(biāo)記了不允許進(jìn)行unmap操作,將那些在pte表項(xiàng)中有映射到頁(yè)面保留在inactive list中。

3、對(duì)于正在回寫(xiě)中的頁(yè)面,如果是同步操作,等待頁(yè)面回寫(xiě)完成。如果是異步操作,將page繼續(xù)留在inactive list中,等待以后掃描再回收釋放。

4、如果檢查到page又被訪問(wèn)了,這個(gè)時(shí)候page有一定的機(jī)會(huì)回到active list鏈表中。必須滿足

? ? a. page被訪問(wèn),page_referenced檢查

? ? b. order小于3,也就是系統(tǒng)趨向于回收較大的頁(yè)面。對(duì)于較小的頁(yè)面 趨向于保留在active list中

? ? c. page_mapping_inuse檢查

5、如果是匿名頁(yè)面,并且不在swap緩沖區(qū)中,將page加入到swap的緩沖區(qū)

6、如果頁(yè)面被映射了,調(diào)用unmap函數(shù)

7、如果頁(yè)面是臟頁(yè),需要向?qū)㈨?yè)面內(nèi)容換出,調(diào)用pateout

8、如果頁(yè)面和buffer相關(guān)聯(lián),將buffer釋放掉,調(diào)用try_to_release_page函數(shù),調(diào)用__remove_mapping 將頁(yè)面回收歸還伙伴系統(tǒng)


為何需要文件系統(tǒng)?手機(jī)主流文件系統(tǒng)概況(f2fs/ext4)

文件系統(tǒng):

? ? ? ? Linux以文件的形式對(duì)計(jì)算機(jī)中的數(shù)據(jù)和硬件資源進(jìn)行管理,也就是徹底的一切皆文件,反映在Linux的文件類(lèi)型上就是:普通文件、目錄文件(也就是文件夾)、設(shè)備文件、鏈接文件、管道文件、套接字文件(數(shù)據(jù)通信的接口)等等。而這些種類(lèi)繁多的文件被Linux使用目錄樹(shù)進(jìn)行管理, 所謂的目錄樹(shù)就是以根目錄(/)為主,向下呈現(xiàn)分支狀的一種文件結(jié)構(gòu)。不同于純粹的ext2之類(lèi)的文件系統(tǒng),我把它稱為文件體系,一切皆文件和文件目錄樹(shù)的資源管理方式一起構(gòu)成了Linux的文件系統(tǒng),讓Linux操作系統(tǒng)可以方便使用系統(tǒng)資源。


手機(jī)主流文件系統(tǒng)概況:

? ? ? ? 文件系統(tǒng)的作用是確定如何在本地存儲(chǔ)中存儲(chǔ)和檢索數(shù)據(jù)。Android操作系統(tǒng)通常使用ext4文件系統(tǒng),相較于前代ext3文件系統(tǒng),ext4能快速更新文件存儲(chǔ)。

ext4:

? ? ? ? ext4文件系統(tǒng)從ext3/ext2文件系統(tǒng)繼承發(fā)展而來(lái),ext4相較于前代,Ext4的文件系統(tǒng)容量達(dá)到1EB,而文件容量則達(dá)到16TB;采用新的數(shù)據(jù)分配方式(持久性預(yù)分配、延時(shí)分配、多塊分配)以及在線碎片整理來(lái)減少磁盤(pán)碎片化,此外還增加了元數(shù)據(jù)校驗(yàn)和,改進(jìn)了時(shí)間戳和快速文件檢查等功能。常用作存放系統(tǒng)文件,這種IO讀寫(xiě)少的。


主要屬性介紹:

Superblock:超級(jí)塊,一個(gè)文件系統(tǒng)有一個(gè),每個(gè)塊組也會(huì)包含超級(jí)塊的副本。含有文件系統(tǒng)的屬性和接口:

? ? 屬性:文件系統(tǒng)的一些參數(shù);

? ? 接口:mount和umount接口等。

Inode:每個(gè)文件(包括文件夾)都有一個(gè)Inode,含有文件的屬性和文件屬性的接口。

? ? 屬性:文件名,創(chuàng)建時(shí)間,修改時(shí)間,訪問(wèn)權(quán)限,文件保存的LBA等;

? ? 接口:創(chuàng)建,刪除文件夾等。

Dentry :每個(gè)目錄都有一個(gè),用來(lái)方便目錄查找等。訪問(wèn)文件的時(shí)候,用戶傳遞文件路徑,VFS通過(guò)Hash樹(shù)查找的方法直接通過(guò)路徑查到最終Dentry,并找到inode,通過(guò)hash查找,最快一次就能找到,不需要逐級(jí)查找。

? ? 屬性:目錄名等;

? ? 接口:查找文件路徑等。

File :對(duì)文件進(jìn)行操作的接口,常用于讀寫(xiě)操作。

? ? 屬性:文件鎖,當(dāng)前訪問(wèn)的偏移地址等;

? ? 接口:fopen,fclose,fwrite,fread,fsync,異步讀寫(xiě)等。

inode bitmap:標(biāo)簽分布表,表示標(biāo)簽表inode table哪些條目是占用的,用一個(gè)bit是0或者1表示空或者非空。

block bitmap:盒子分布表,表示哪些盒子里面有數(shù)據(jù),用一個(gè)bit是0或者1表示空或者非空

For example:

查找文件 example:/root/test/a.txt

(一)通過(guò)內(nèi)核找到根目錄/的inode

1、根據(jù)根目錄/的inode,到inode table中找到根目錄/的塊指針

2、通過(guò)塊指針找到根目錄/的數(shù)據(jù)塊,根據(jù)其中的數(shù)據(jù)找到下級(jí)目錄/root/對(duì)應(yīng)的inode

3、根據(jù)/root/對(duì)應(yīng)的inode,到inode table中找到目錄/root/的元數(shù)據(jù)及塊指針

4、通過(guò)塊指針找到存放目錄/root/的數(shù)據(jù)塊,根據(jù)其中數(shù)據(jù)找到/root/test/目錄對(duì)應(yīng)的inode

5、根據(jù)/root/test/目錄對(duì)應(yīng)的inode,到inode table中找到目錄/root/test/的元數(shù)據(jù)及塊指針

6、通過(guò)塊指針找到存放目錄/root/test/的數(shù)據(jù)塊,根據(jù)其中數(shù)據(jù)找到文件/root/test/a.txt對(duì)應(yīng)的inode

7、根據(jù)文件/root/test/a.txt對(duì)應(yīng)的inode到inode table中找到文件/root/test/a.txt的元數(shù)據(jù)及塊指針

8、通過(guò)塊指針找到存放文件/root/test/a.txt的數(shù)據(jù)塊

II.創(chuàng)建文件 example:/root/test/b.txt

1、掃描inode bitmap,找到一個(gè)空閑的inode,將其標(biāo)記為占用,獲取其對(duì)應(yīng)的inode number

2、查找目錄/root/test/的數(shù)據(jù)(過(guò)程參考I),并在其中添加一條目錄項(xiàng)(dirent)記錄,文件名為/root/test/b.txt,inode number在步驟1中已經(jīng)獲得

3、根據(jù)inode number,在inode table中找到該inode,記錄文件/root/test/b.txt的部分元數(shù)據(jù),如inode number、權(quán)限等等

4、掃描block bitmap,找到可分配的空閑塊,標(biāo)記為占用,并在文件/root/test/b.txt的元數(shù)據(jù)中記錄塊指針

5、在數(shù)據(jù)塊中寫(xiě)入文件數(shù)據(jù)。

III.刪除文件 example:/root/test/c.txt

1、查找文件/root/test/c.txt使用的元數(shù)據(jù)信息(過(guò)程參考I)

2、查找目錄/root/test/的數(shù)據(jù)(過(guò)程參考I),并刪除文件/root/test/c.txt的目錄項(xiàng)(dirent)記錄

3、修改文件/root/test/c.txt的元數(shù)據(jù),將其鏈接數(shù)-1

4、如果此時(shí)文件/root/test/c.txt的鏈接數(shù)≤0,掃描block bitmap,將分配給文件的塊節(jié)點(diǎn)標(biāo)記為空閑

5、如果此時(shí)文件/root/test/c.txt的鏈接數(shù)≤0,掃描inode bitmap,將其中對(duì)應(yīng)的節(jié)點(diǎn)標(biāo)記為空閑

f2fs:

? ? ? ? f2fs全名為“Flash Friendly File System”這是一種專門(mén)為閃存而生的,較為新型的支持Linux內(nèi)核的文件系統(tǒng)。最早是由三星在2012年研發(fā)設(shè)計(jì)的,其目的就是為了更好的適應(yīng) NAND 一類(lèi)的閃存設(shè)備(例如固態(tài)硬盤(pán)、eMMC和SD卡等),在f2fs中三星應(yīng)用了日志結(jié)構(gòu)檔案系統(tǒng)的概念,使它更適合用于儲(chǔ)存設(shè)備。f2fs的優(yōu)勢(shì)通俗來(lái)說(shuō)就是小文件的傳輸速率變快了。不過(guò)問(wèn)題也很明顯,將相同文件存儲(chǔ)到f2fs文件格式下相較于ext4會(huì)占用1.1倍到1.5倍的空間。

? ? ? ? f2fs選擇 log-structured文件系統(tǒng)方案,并使之更加適應(yīng)新的存儲(chǔ)介質(zhì)(NAND)。同時(shí),修復(fù)了舊式日志結(jié)構(gòu)文件系統(tǒng)的一些已知問(wèn)題,如wandering tree 的滾雪球效應(yīng)和高清理開(kāi)銷(xiāo)。

? ? ? ? 根據(jù)內(nèi)部幾何結(jié)構(gòu)和閃存管理機(jī)制(FTL),閃存存儲(chǔ)設(shè)備有很多不同的屬性,所以F2FS的設(shè)計(jì)者增加了多種參數(shù),不僅用于配置磁盤(pán)布局,還可以選擇分配和清理算法,優(yōu)化性能(并行IO提高性能)。

ION內(nèi)存概述

? ? ? ? ION是Google在Android4.0以后,為了解決內(nèi)存碎片管理而引入的通用內(nèi)存管理器。用戶空間、內(nèi)核驅(qū)動(dòng)均可以使用ION分配內(nèi)存,除此之外,ION也提供多個(gè)Client之間共享內(nèi)存。SurfaceFlinger/Camera/Audio都常使用ION。

從2^8次方內(nèi)存開(kāi)始分配,一次就是1M。沒(méi)有的話就是2^4,然后是2^0。本身有池

android S開(kāi)始采用DMA_BUF替換ION,主要是為了讓kernel社區(qū)接納ion維護(hù)...其他變化不大

zsmalloc 用于內(nèi)核內(nèi)存壓縮

dma_alloc_coherent DMA內(nèi)存分配N(xiāo)個(gè)pages,目前kernel實(shí)現(xiàn)是從CMA中分配,物理連續(xù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 本文以32位機(jī)器為準(zhǔn),串講一些內(nèi)存管理的知識(shí)點(diǎn)。 1. 虛擬地址、物理地址、邏輯地址、線性地址 虛擬地址又叫線性地...
    linux服務(wù)器開(kāi)發(fā)閱讀 2,183評(píng)論 0 0
  • 正文 0 內(nèi)存模塊 1 linux內(nèi)存總體布局:內(nèi)存分成用戶態(tài)和內(nèi)核態(tài) 4G進(jìn)程地址空間解析 內(nèi)核地址空間 進(jìn)程地...
    mfdalf閱讀 6,962評(píng)論 0 19
  • 進(jìn)程 創(chuàng)建 創(chuàng)建進(jìn)程用fork()函數(shù)。fork()為子進(jìn)程創(chuàng)建新的地址空間并且拷貝頁(yè)表。子進(jìn)程的虛擬地址空間...
    梅花怒閱讀 2,088評(píng)論 0 7
  • Page Cache是通過(guò)將磁盤(pán)中的數(shù)據(jù)緩存到內(nèi)存中,減少磁盤(pán)I/O操作,從而提高性能。此外,還要確保Page C...
    Balram閱讀 4,216評(píng)論 0 3
  • 所謂進(jìn)程地址空間(process address space),就是從進(jìn)程的視角看到的地址空間,是進(jìn)程運(yùn)行時(shí)所用到...
    tracy_668閱讀 1,675評(píng)論 0 0

友情鏈接更多精彩內(nèi)容