Linux 內(nèi)存管理分析

1. 用戶空間

通常 32 位 Linux 虛擬地址空間劃分, 0-3GB為用戶空間,3GB-4GB為內(nèi)核空間脂新。每個進(jìn)程都有4GB的虛擬地址空間挪捕,其中0-3GB是自己私有的用戶空間,最高的1GB是與所有進(jìn)程共享的內(nèi)核空間争便。Linux 進(jìn)程的內(nèi)存布局如下圖所示:

進(jìn)程虛擬地址空間

進(jìn)程地址空間主要分為以下幾部分:
代碼段(Text): 程序代碼在內(nèi)存中的映射级零,存放函數(shù)體的二進(jìn)制代碼。
數(shù)據(jù)段(Data): 在程序運(yùn)行初已經(jīng)對變量進(jìn)行初始化的數(shù)據(jù)滞乙。
BSS段(BSS): 在程序運(yùn)行初未對變量進(jìn)行初始化的數(shù)據(jù)奏纪。
棧(Stack): 存儲局部,臨時(shí)變量斩启,函數(shù)調(diào)用時(shí)存儲函數(shù)的返回指針亥贸,用于控制函數(shù)的調(diào)用和返回。在程序塊開始時(shí)自動分配內(nèi)存浇垦,結(jié)束時(shí)自動釋放內(nèi)存炕置,其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧荣挨。
堆(Heap): 存儲動態(tài)內(nèi)存分配,需要程序員手工分配朴摊,手工釋放默垄。

注意,以上所說的地址均為虛擬地址甚纲。進(jìn)程虛擬地址到物理地址的轉(zhuǎn)換會在下面"段頁式存儲管理"部分詳細(xì)講解口锭。

2. 內(nèi)核空間

在Linux中,內(nèi)核空間是持續(xù)存在的介杆,并且在所有進(jìn)程中都映射到同樣的物理內(nèi)存鹃操,內(nèi)核代碼和數(shù)據(jù)總是可尋址的,隨時(shí)準(zhǔn)備處理中斷和系統(tǒng)調(diào)用春哨。

物理地址 = 邏輯地址 – 0xC0000000荆隘,這是內(nèi)核地址空間3GB - 3GB+896MB的地址轉(zhuǎn)換關(guān)系,說白了就是線性映射赴背,偏移為0xC0000000椰拒。注意內(nèi)核的虛擬地址在“高端”,但是它映射的物理內(nèi)存地址在低端凰荚。

為什么只有3GB - 3GB+896MB是線性映射燃观,而不是整個1GB都線性映射呢吏口?假設(shè)按照這樣簡單的地址映射關(guān)系糙俗,那么內(nèi)核地址空間訪問為3GB-4GB,對應(yīng)的物理內(nèi)存范圍就為0-1GB邑狸,即只能訪問1GB物理內(nèi)存到涂。若機(jī)器中安裝4G物理內(nèi)存脊框,那么內(nèi)核就只能訪問前1G物理內(nèi)存,后面3G物理內(nèi)存將會無法訪問养盗。為了解決這個問題缚陷,Linux引入了高端內(nèi)存的概念。

高端內(nèi)存的基本思想:借一段地址空間往核,建立臨時(shí)地址映射箫爷,用完后釋放。達(dá)到這段地址空間可以循環(huán)使用聂儒,訪問所有物理內(nèi)存的目的虎锚。

內(nèi)核空間

Linux系統(tǒng)在初始化時(shí),會根據(jù)實(shí)際的物理內(nèi)存的大小衩婚,為每個物理頁面創(chuàng)建一個page對象窜护,所有的page對象構(gòu)成一個mem_map數(shù)組。進(jìn)而針對不同的用途非春,Linux內(nèi)核將所有的物理頁面劃分到3類內(nèi)存管理區(qū)中柱徙,如圖缓屠,分別為ZONE_DMA,ZONE_NORMAL护侮,ZONE_HIGHMEM敌完。

Zone

ZONE_DMA的范圍是0-16MB,該區(qū)域的物理頁面專門供I/O設(shè)備的DMA使用羊初。之所以需要單獨(dú)管理DMA的物理頁面滨溉,是因?yàn)镈MA使用物理地址訪問內(nèi)存,不經(jīng)過MMU长赞,并且需要連續(xù)的緩沖區(qū)晦攒,所以為了能夠提供物理上連續(xù)的緩沖區(qū),必須從物理地址空間專門劃分一段區(qū)域用于DMA得哆。
ZONE_NORMAL的范圍是16MB-896MB脯颜,該區(qū)域的物理頁面是內(nèi)核能夠直接使用的。
ZONE_HIGHMEM的范圍是896MB-4GB柳恐,該區(qū)域即為高端內(nèi)存伐脖,內(nèi)核不能直接使用热幔。

3. 段頁式存儲管理

程序在執(zhí)行時(shí)乐设,傳遞給CPU的地址是邏輯地址。它由兩部分組成绎巨,一部分是段選擇符(比如cs和ds等段寄存器的值)近尚,另一部分是偏移量(比如eip寄存器的值)。邏輯地址必須經(jīng)過段式映射轉(zhuǎn)換為線性地址场勤,線性地址再經(jīng)過頁式映射轉(zhuǎn)為物理地址戈锻,才能訪問真正的物理內(nèi)存。轉(zhuǎn)換過程如下:

段頁式存儲管理

3.1 段式映射

邏輯地址是以"段寄存器:偏移地址"形式存在的和媳。段寄存器是一個16位的寄存器格遭, 其中第0和1位控制著將要訪問段的特權(quán)級別。第2位說明是在GDT還是LDT中尋找地址留瞳,Linux程序里用的段描述符總是選擇GDT拒迅。高13位作為一個索引值。

段寄存器

如下圖所示她倘,首先從GDTR寄存器中取出段描述符表(GDT)的首地址璧微,通過段寄存器里的索引值,可以從段描述符表(GDT)里找到段的基址硬梁。 然后用基址加上段內(nèi)的偏移量前硫,就得到了對應(yīng)的線性地址。

邏輯地址->線性地址

3.2 頁式映射

內(nèi)核把物理頁作為內(nèi)存管理的基本單位荧止,頁面大小為4KB屹电,整個虛擬地址空間為4GB阶剑,則需要包含1M個頁表項(xiàng),這還只是一個進(jìn)程危号,因?yàn)槊總€進(jìn)程都有自己獨(dú)立的頁表个扰,這樣系統(tǒng)所有的內(nèi)存都來存放頁表項(xiàng)恐怕都不夠。想象一下進(jìn)程的虛擬地址空間葱色,實(shí)際上大部分是空閑的递宅,真正映射的區(qū)域幾乎是汪洋大海中的小島,因次我們可以考慮使用多級頁表苍狰,可以減少頁表內(nèi)存使用量办龄。Linux操作系統(tǒng)使用4級頁表,4級頁表分別為:頁全局目錄淋昭、頁上級目錄俐填、頁中間目錄、頁表翔忽。

線性地址->物理地址

4. Buddy

Linux采用著名的伙伴系統(tǒng)(buddy system)算法來解決外碎片問題英融。把所有的空閑頁框分組為11個塊鏈表,每個塊鏈表分別包含大小為1歇式,2驶悟,4,8材失,16痕鳍,32,64龙巨,128笼呆,256,512和1024個連續(xù)的頁框旨别。對1024個頁框的最大請求對應(yīng)著4MB大小的連續(xù)RAM塊诗赌。每個塊的第一個頁框的物理地址是該塊大小的整數(shù)倍。
伙伴算法是一種物理內(nèi)存分配和回收的方法秸弛,物理內(nèi)存所有空閑頁都記錄在BUDDY鏈表中铭若。系統(tǒng)建立一個鏈表,鏈表中的每個元素代表一類大小的物理內(nèi)存胆屿,分別為2的0次方奥喻、1次方、2次方...個頁大小非迹,對應(yīng)4K环鲤、8K、16K...的內(nèi)存憎兽,每一類大小的內(nèi)存又有一個鏈表冷离,表示目前可以分配的物理內(nèi)存吵冒。例如現(xiàn)在僅存需要分配8K的物理內(nèi)存,系統(tǒng)首先從8K那個鏈表中查詢有無可分配的內(nèi)存西剥,若有直接分配痹栖;否則查找16K大小的鏈表,若有瞭空,首先將16K一分為二揪阿,將其中一個分配給進(jìn)程,另一個插入8K的鏈表中咆畏,若無南捂,繼續(xù)查找32K,若有旧找,首先把32K一分為二溺健,其中一個16K大小的內(nèi)存插入16K鏈表中,然后另一個16K繼續(xù)一分為二钮蛛,將其中一個插入8K的鏈表中鞭缭,另一個分配給進(jìn)程,以此類推魏颓。當(dāng)內(nèi)存釋放時(shí)岭辣,查看相鄰內(nèi)存有無空閑,若存在兩個聯(lián)系的8K的空閑內(nèi)存琼开,直接合并成一個16K的內(nèi)存易结,插入16K鏈表中枕荞。

Buddy 算法

采用伙伴算法分配內(nèi)存時(shí)柜候,每次至少分配一個頁面。但當(dāng)請求分配的內(nèi)存大小為幾十個字節(jié)或幾百個字節(jié)時(shí)應(yīng)該如何處理躏精?如何在一個頁面中分配小的內(nèi)存區(qū)渣刷,小內(nèi)存區(qū)的分配所產(chǎn)生的內(nèi)碎片又如何解決?Linux采用Slab矗烛。

5. Slab

slab向buddy“批發(fā)”一些內(nèi)存辅柴,加工切塊以后“散賣”出去。
slab分配器主要的功能就是對頻繁分配和釋放的小對象提供高效的內(nèi)存管理瞭吃。它的核心思想是實(shí)現(xiàn)一個緩存池碌嘀,分配對象的時(shí)候從緩存池中取,釋放對象的時(shí)候再放入緩存池歪架。slab分配器是基于對象類型進(jìn)行內(nèi)存管理的股冗,每一種對象被劃分為一類,例如索引節(jié)點(diǎn)對象是一類和蚪,進(jìn)程描述符又是一類止状,等等烹棉。每當(dāng)需要申請一個特定的對象時(shí),就從相應(yīng)的類中分配一個空白的對象出去怯疤;當(dāng)這個對象被使用完畢時(shí)浆洗,就重新“插入”到相應(yīng)的類中(其實(shí)并不存在插入的動作,僅僅是將該對象重新標(biāo)記為空閑而已)集峦。

Slab
  1. 首先要查看inode_cachep的slabs_partial鏈表伏社,如果slabs_partial非空,就從中選中一個slab塔淤,返回一個指向已分配但未使用的inode結(jié)構(gòu)的指針洛口。完事之后,如果這個slab滿了凯沪,就把它從slabs_partial中刪除第焰,插入到slabs_full中去,結(jié)束妨马;

  2. 如果slabs_partial為空挺举,也就是沒有半滿的slab,就會到slabs_empty中尋找烘跺。如果slabs_empty非空湘纵,就選中一個slab,返回一個指向已分配但未使用的inode結(jié)構(gòu)的指針滤淳,然后將這個slab從slabs_empty中刪除梧喷,插入到slabs_partial(或者slab_full)中去,結(jié)束脖咐;

  3. 如果slabs_empty也為空铺敌,那么沒辦法,cache內(nèi)存已經(jīng)不足屁擅,只能新創(chuàng)建一個slab了偿凭。

Slab分配器一直處于內(nèi)核內(nèi)存管理的核心地位,盡管如此派歌,它還是擁有自身的缺點(diǎn)弯囊,最明顯的兩點(diǎn)就是復(fù)雜性和過多的管理數(shù)據(jù)造成的內(nèi)存上的開銷。針對這些問題胶果,linux引入了slub分配器匾嘱,

6. Slub

slub分配器保留了slab分配器的所有接口,實(shí)際上slub分配器的模型和slab分配的模型是基本一致的早抠,只不過在一些地方進(jìn)行了精簡霎烙,這也使得slub分配器工作起來更為游刃有余。兩者主要的區(qū)別如下:

  1. slab分配器為了增加分配速度,引入了一些管理數(shù)組吼过,如slab管理區(qū)中的kmem_bufctl數(shù)組和緊隨本地CPU結(jié)構(gòu)后面的用來跟蹤最熱空閑對象的數(shù)組锐秦,這些結(jié)構(gòu)雖然加快了分配對象的速度,但也增加了一定的復(fù)雜性盗忱,而且隨著系統(tǒng)變得龐大酱床,其對內(nèi)存的開銷也越明顯,而slub分配器則完全摒棄了這些管理數(shù)據(jù)趟佃。
  2. slab分配器針對每個緩存扇谣,根據(jù)slab的狀態(tài)劃分了3個鏈表 full,partial和free。slub分配器做了簡化闲昭,去掉了free鏈表罐寨,對于空閑的slab,slub分配器選擇直接將其釋放序矩。
  3. slub分配器摒棄了slab分配器中的著色概念鸯绿,在slab分配器中,由于顏色的個數(shù)有限簸淀,因此著色也無法完全解決slab之間的緩存行沖突問題瓶蝴,考慮到著色造成了內(nèi)存上的浪費(fèi),slub分配器沒有引入著色租幕。
  4. 在NUMA架構(gòu)的支持上舷手,slub分配器也較slab分配器做了簡化。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末劲绪,一起剝皮案震驚了整個濱河市男窟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贾富,老刑警劉巖歉眷,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異祷安,居然都是意外死亡姥芥,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門汇鞭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人庸追,你說我怎么就攤上這事霍骄。” “怎么了淡溯?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵读整,是天一觀的道長。 經(jīng)常有香客問我咱娶,道長米间,這世上最難降的妖魔是什么强品? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮屈糊,結(jié)果婚禮上的榛,老公的妹妹穿的比我還像新娘。我一直安慰自己逻锐,他們只是感情好夫晌,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著昧诱,像睡著了一般晓淀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盏档,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天凶掰,我揣著相機(jī)與錄音,去河邊找鬼蜈亩。 笑死锄俄,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的勺拣。 我是一名探鬼主播奶赠,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼药有!你這毒婦竟也來了毅戈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤愤惰,失蹤者是張志新(化名)和其女友劉穎苇经,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宦言,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扇单,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奠旺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蜘澜。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖响疚,靈堂內(nèi)的尸體忽然破棺而出鄙信,到底是詐尸還是另有隱情,我是刑警寧澤忿晕,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布装诡,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏鸦采。R本人自食惡果不足惜宾巍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渔伯。 院中可真熱鬧顶霞,春花似錦、人聲如沸咱旱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吐限。三九已至鲜侥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诸典,已是汗流浹背描函。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留狐粱,地道東北人舀寓。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像肌蜻,于是被迫代替她去往敵國和親互墓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容