在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Linux的內(nèi)存管理是什么,Linux的內(nèi)存管理詳解

Linux內(nèi)核補(bǔ)給站 ? 來(lái)源:Linux內(nèi)核補(bǔ)給站 ? 作者:Linux內(nèi)核補(bǔ)給站 ? 2022-05-11 17:54 ? 次閱讀

Linux的內(nèi)存管理

Linux的內(nèi)存管理是一個(gè)非常復(fù)雜的過(guò)程,主要分成兩個(gè)大的部分:內(nèi)核的內(nèi)存管理和進(jìn)程虛擬內(nèi)存。內(nèi)核的內(nèi)存管理是Linux內(nèi)存管理的核心,所以我們先對(duì)內(nèi)核的內(nèi)存管理進(jìn)行簡(jiǎn)介。

一、物理內(nèi)存模型


pYYBAGJ7h8qAfJe-AAA3U8e_SDc509.jpg?source=d16d100b

?

物理內(nèi)存模型主要分為兩種:UMA(Uniform Memory Access)和NUMA(Non-Uniform Memory Access)。

UMA模型是指物理內(nèi)存是連續(xù)的,SMP系統(tǒng)中的每個(gè)處理器訪問(wèn)各個(gè)內(nèi)存區(qū)都是同樣快的;而NUMA模型則是指SMP中的每個(gè)CPU都有自己的物理內(nèi)存區(qū),雖然CPU可以訪問(wèn)其他CPU的內(nèi)存區(qū),但是要比方位自己的內(nèi)存區(qū)慢得多。我們一般使用的物理模型都是UMA模型。為了NUMA模型,Linux提供了三種可能的內(nèi)存布局配置:Flat Memory, Sparse Memory, Discontiguous Memory。


poYBAGJ7h8qAFB54AACVOF1bFvY111.jpg?source=d16d100b

?

Flat Memory就是簡(jiǎn)單的線性組織物理內(nèi)存,一般沒(méi)有內(nèi)存空洞的UMA架構(gòu)都采用這種配置。對(duì)于NUMA模型,一般只能采用后兩者,而后兩者的區(qū)別主要在于:Sparse Memory配置一般認(rèn)為是試驗(yàn)性的,不是那么穩(wěn)定,但是有一些新的功能和性能優(yōu)化,而Discontiguous Memory配置一般認(rèn)為是穩(wěn)定的,但不具有內(nèi)存熱插拔之類(lèi)的新特性。

二、物理內(nèi)存組織

  • 物理內(nèi)存的組織主要分為兩個(gè)部分:節(jié)點(diǎn)(node)和內(nèi)存與內(nèi)存域(zone)。
  • node主要針對(duì)NUMA設(shè)計(jì),在NUMA的SMP系統(tǒng)中,每個(gè)處理器都有一個(gè)自己的node,而在UMA模型中則只有一個(gè)node。對(duì)于每個(gè)node中的內(nèi)存,Linux分成了若干內(nèi)存域,定義在mmzone.h的zone_type中,常用的有ZONE_DMA、ZONE_DMA32、ZONE_NORMAL、ZONE_HIGHMEM和ZONE_MOVABLE。其中ZONE_NORMAL是最為常用的,表示內(nèi)核能夠直接映射的一般內(nèi)存區(qū)域;ZONE_DMA表示DMA內(nèi)存區(qū);ZONE_DMA32表示64位系統(tǒng)中對(duì)于32位DMA設(shè)備使用的內(nèi)存;ZONE_HIGHMEM表示在32位系統(tǒng)中,高地址內(nèi)存的區(qū)域;ZONE_MOVABLE與伙伴系統(tǒng)的內(nèi)存碎片消除有關(guān)。后文會(huì)詳細(xì)介紹相關(guān)部分。
  • 在物理內(nèi)存管理過(guò)程中有一些名詞:
  1. Page Frame(頁(yè)幀,或稱(chēng)頁(yè)框):是系統(tǒng)內(nèi)存管理的最小單位,系統(tǒng)中每個(gè)頁(yè)框都是struct page的一個(gè)實(shí)例。IA-32系統(tǒng)的頁(yè)框大小是4KB。
  2. Hot-n-Code Pages(冷熱頁(yè)):是指內(nèi)存管理中對(duì)頁(yè)框的分類(lèi),訪問(wèn)較多的或者近期訪問(wèn)的為熱頁(yè),否則為冷頁(yè)。該標(biāo)記主要與內(nèi)存換出(memory swap)相關(guān)。
  3. Page Table(頁(yè)表):是內(nèi)存尋址過(guò)程中的輔助數(shù)據(jù)結(jié)構(gòu)。層次化的頁(yè)表對(duì)于大地之空間的快速、高效管理很有意義。Linux一般支持四級(jí)頁(yè)表:PGD(Page Global Directory)、PUD(Page Upper Directory)、PMD(Page Middle Directory)和PTE(Page Table Entry)。IA-32體系中默認(rèn)只是用了兩級(jí)分頁(yè)系統(tǒng),即只有PGD和PTE。

三、X86架構(gòu)下的內(nèi)存布局

內(nèi)核在內(nèi)存中的布局

Linux的內(nèi)核在初始化的時(shí)候會(huì)被加載到內(nèi)存區(qū)的固定位置(在此我們不討論可重定位內(nèi)核的情況),而內(nèi)核所占用的內(nèi)存區(qū)域的布局是固定的,如圖:


pYYBAGJ7h8qAAVYKAACGj-7Qi5s581.jpg?source=d16d100b

?

內(nèi)存第一個(gè)頁(yè)框不實(shí)用,主要被BIOS用來(lái)初始化;之后的連續(xù)640KB內(nèi)存也不被內(nèi)核使用,主要用來(lái)映射各種ROM(通常是BIOS和顯卡ROM);再之后的空間是閑置的,原因是內(nèi)核要被放在連續(xù)的內(nèi)存空間。在0x100000開(kāi)始為內(nèi)核部分,分別是代碼段、數(shù)據(jù)段和附加段。

IA-32架構(gòu)的布局

IA-32架構(gòu)可以訪問(wèn)4GB的地址空間(不考慮PAE),常規(guī)情況下會(huì)將4GB線性空間劃分成3:1的兩部分:低地址的3/4部分為用戶(hù)空間,而高地址的1GB是內(nèi)核空間,即內(nèi)核地址空間從偏移量0xC0000000開(kāi)始,每個(gè)虛擬地址x都對(duì)應(yīng)于物理地址x-0xC0000000。這樣的設(shè)計(jì)加快了內(nèi)核空間尋址的速度(簡(jiǎn)單的減法操作)。在進(jìn)程切換的過(guò)程中,只有用戶(hù)空間的低3GB內(nèi)存對(duì)應(yīng)的頁(yè)表會(huì)被切換,高地址空間會(huì)公用內(nèi)核頁(yè)表。

IA-32架構(gòu)的這種設(shè)計(jì)存在著一個(gè)問(wèn)題:既然內(nèi)核只能處理1GB的空間(事實(shí)上,內(nèi)核處理的空間還不足1GB,后面會(huì)詳細(xì)說(shuō)明),那么如果物理內(nèi)存大于1GB,剩下的內(nèi)存將如何處理?這種情況下,內(nèi)核將無(wú)法直接映射全部物理內(nèi)存,這樣就用到了上面所說(shuō)的高地址內(nèi)存域(ZONE_HIGHMEM)。具體的內(nèi)存分配如下圖:


poYBAGJ7h8qAeuIIAACB3dFVSlQ318.jpg?source=d16d100b

?

能夠看到內(nèi)核區(qū)域的映射從__PAGE_OFFSET(0xC00000)開(kāi)始,即3GiB位置開(kāi)始映射到4GiB,開(kāi)始的一段用來(lái)直接映射,而后面有128MB的VMALLOC空間(這部分空間的使用后文將講到),再之后有永久映射和固定映射的空間(從PKMAP_BASE開(kāi)始)。所以事實(shí)上物理內(nèi)存能夠直接映射的空間為1GB-VMALLOC-固定映射-永久映射,所以真正大約只有850MB多一點(diǎn),也就是說(shuō),物理內(nèi)存中只有前850多MB是可以直接映射到內(nèi)核空間的,對(duì)于超過(guò)的部分來(lái)說(shuō),將作為高地址空間(HIGHMEM)。高地址空間可以在VMALLOC、永久映射和固定映射部分使用到。

到這里可能會(huì)有這樣一個(gè)疑問(wèn):如果內(nèi)核只能處理896MB的空間,那么如果內(nèi)存很大(比如3GB),剩下的空間的利用率和利用效率豈不是很低?對(duì)于這個(gè)問(wèn)題我們需要注意:這里我們所講述的:1、這里的內(nèi)存都是內(nèi)核在內(nèi)核區(qū)的1GB空間里對(duì)物理內(nèi)存的訪問(wèn),用戶(hù)對(duì)物理內(nèi)存的訪問(wèn)不是通過(guò)直接映射來(lái)訪問(wèn)的,還有另外一套機(jī)制;2、這里的內(nèi)存僅僅是通過(guò)直接映射得到的內(nèi)存,內(nèi)核還可以通過(guò)其他的方式訪問(wèn)到較高地址的內(nèi)存。

還有一個(gè)普遍的疑問(wèn)就是:內(nèi)核直接映射占用了800多MB的空間,那么如果我們又3GB的物理內(nèi)存,是不是只有2GB多一點(diǎn)的實(shí)際可用內(nèi)存呢?這個(gè)說(shuō)法是錯(cuò)誤的,上圖所描述的只是內(nèi)核在線性地址空間的分布情況,其中的任何區(qū)域如果沒(méi)有真正的物理內(nèi)存與之映射的話是不會(huì)真正占用物理內(nèi)存的,而物理內(nèi)存在分配的過(guò)程中(用戶(hù)申請(qǐng)內(nèi)存、VMALLOC部分等),更傾向于先分配高地址內(nèi)存,在高地址內(nèi)存耗盡的情況下才會(huì)使用低850MB內(nèi)存。

AMD64架構(gòu)的布局

AMD64架構(gòu)采用了與IA-32完全不同的布局模式。由于64位的尋址空間的64位長(zhǎng),而在真正的實(shí)現(xiàn)過(guò)程中64位長(zhǎng)尋址會(huì)造成較大的開(kāi)銷(xiāo),所以Linux目前僅適用了48位長(zhǎng)的地址空間,但是為了向后兼容仍然適用64位地址空間表示。在布局方面考慮,如果單純采用48位類(lèi)似IA-32的布局方式的話,則很難保證向后兼容性。所以AMD64架構(gòu)下的內(nèi)存布局Linux采用了一種特殊的方式,如圖:


pYYBAGJ7h8qAHyp0AACoBAEKKxU508.jpg?source=d16d100b

?

Linux將內(nèi)存分成了高地址部分和低地址部分兩部分,即下半部空間0~0x0000 7FFF FFFF FFFF和上半部空間0xFFFF 8000 0000 0000~0xFFFF FFFF FFFF FFFF。可以看到虛擬地址的低47位,即[0,46]為有效位,[47,63]的值總是相同的:或者全為0或者全為1。除此之外的值都是無(wú)效的。這樣在虛擬內(nèi)存空間中就將內(nèi)存分成了兩個(gè)部分:內(nèi)存空間的下半部和上半部。下半部為用戶(hù)空間,上半部為內(nèi)核空間。我們考慮內(nèi)核空間部分,下半部的前MAXMEM大小(64TB)為直接映射地址,之后有一個(gè)空洞,主要目的是處理內(nèi)存訪問(wèn)越界;再之后是大小為32TB的VMALLOC空間,在之后是VMMEMMAP空間、KERNEL TEXT段空間以及Modules空間。

在這里我們不仔細(xì)講述AMD64架構(gòu)的布局,以后的部分則主要關(guān)注于IA-32架構(gòu)。

四、啟動(dòng)過(guò)程期間的內(nèi)存管理

在啟動(dòng)過(guò)程中,盡管內(nèi)存管理尚未初始化,但內(nèi)核仍然需要分配內(nèi)存以創(chuàng)建各種數(shù)據(jù)結(jié)構(gòu)。bootmem分配器用于在啟動(dòng)階段早期分配內(nèi)存。由于對(duì)這部分內(nèi)存分配集中于簡(jiǎn)單性方面而不是性能和通用性,因此使用的是最先適配(first-fit)分配器。該分配器使用一個(gè)位圖來(lái)管理頁(yè),位圖中的1表示頁(yè)已使用,0表示未使用。在需要分配內(nèi)存時(shí),分配器掃描位圖,直到找到一個(gè)能夠提供足夠連續(xù)頁(yè)的為之,即最先最佳(first-best)或最先適配位置。

在這個(gè)分配過(guò)程中,需要處理一些不可分配的頁(yè)面,如IA-32系統(tǒng)中的0頁(yè)。另外對(duì)于IA-32系統(tǒng),bootmem僅僅使用了低地址部分,對(duì)于高地址部分的操作過(guò)于麻煩,所以在這里被放棄了。

在這個(gè)部分有一個(gè)很有意思的事情。我們?cè)诰帉?xiě)內(nèi)核模塊的時(shí)候,對(duì)于模塊的初始化函數(shù)會(huì)使用__init標(biāo)記或者_(dá)_init_data標(biāo)記。對(duì)于被這兩個(gè)關(guān)鍵字標(biāo)記的函數(shù)和數(shù)據(jù),是只有在初始化階段才用到的,在bootmem退出的時(shí)候會(huì)全部被回收。而這部分代碼和數(shù)據(jù)再內(nèi)核鏈接的過(guò)程中將會(huì)被放在.init.text段和.init.data段,并統(tǒng)一放在內(nèi)核的尾部,在啟動(dòng)結(jié)束后便于回收。

五、物理內(nèi)存的管理

1、伙伴系統(tǒng)

物理內(nèi)存管理中伙伴系統(tǒng)是最為重要的一個(gè)系統(tǒng),伙伴系統(tǒng)也基于一種相對(duì)簡(jiǎn)單然而令人吃驚的強(qiáng)大算法,到目前已經(jīng)使用了幾乎40年?;锇橄到y(tǒng)在這里不再贅述,簡(jiǎn)單谷歌一下就可以查到該算法的描述(實(shí)在是很簡(jiǎn)單)。在這里主要講一下Linux Kernel的伙伴系統(tǒng)以及在2.6.24之后版本的系統(tǒng)中對(duì)伙伴系統(tǒng)的改良。

在上文中已經(jīng)說(shuō)到,物理內(nèi)存的慣例分為若干個(gè)node,每個(gè)node中又有若干個(gè)zone。對(duì)于每個(gè)zone,都會(huì)有對(duì)應(yīng)的伙伴系統(tǒng),如下圖所示:


poYBAGJ7h8qAByEoAABTUqTH21c816.jpg?source=d16d100b

?

上圖中的Fallback list指的是:在多個(gè)node的系統(tǒng)中,如果某個(gè)node的內(nèi)存空間不夠,則會(huì)在Fallback List中指定的node中分配內(nèi)存。

我們可以執(zhí)行cat /proc/buddyinfo,能夠看到大約如下所示的信息:

/proc/buddyinfo:

wolfgang@meitner> cat /proc/buddyinfo

Node 0, zone DMA 3 5 7 4 6 3 3 3 1 1 1

Node 0, zone DMA32 130 546 695 271 107 38 2 2 1 4 479

Node 0, zone Normal 23 6 6 8 1 4 3 0 0 0 0

顯示的三個(gè)域則是我們使用到的內(nèi)存域。

伙伴系統(tǒng)會(huì)出現(xiàn)一個(gè)很常見(jiàn)的問(wèn)題:在系統(tǒng)使用較長(zhǎng)時(shí)間之后,內(nèi)存中經(jīng)常出現(xiàn)較多碎片。對(duì)于這種情況,內(nèi)核將內(nèi)存頁(yè)面分成五種類(lèi)型:

MIGRATE_UNMOVABLE

MIGRATE_RECLAIMABLE

MIGRATE_RESERVE

MIGRATE_MOVABLE

MIGRATE_ISOLATE

其中MIGRATE_RESERVE所表示的內(nèi)存是被系統(tǒng)保留以備急用的;MIGRATE_UNMOVABLE是不可移動(dòng)的,如BIOS信息頁(yè);MIGRATE_RECLAIMABLE在swap系統(tǒng)中使用;MIGRATE_ISOLATE表示不能從這里分配的內(nèi)存;MIGRATE_MOVABLE表示可以移動(dòng)的內(nèi)存。對(duì)于內(nèi)核來(lái)說(shuō),MIGRATE_MOVABLE部分的內(nèi)存可以采用某種算法來(lái)進(jìn)行移動(dòng),使得內(nèi)存中的碎片減少。另外內(nèi)核還維護(hù)了一個(gè)fallback list,來(lái)表示如果在某個(gè)類(lèi)型中分配頁(yè)面未成功,會(huì)在哪些類(lèi)型的頁(yè)面中來(lái)分配。

具體的信息可以在/proc/pagetypeinfo中看到

2、伙伴系統(tǒng)的內(nèi)存分配API

基本上從如下兩張圖就能夠看出來(lái):


pYYBAGJ7h8qAREeSAABYcMJDLT4703.jpg?source=d16d100b

?


poYBAGJ7h8qARHxTAABAYlzSAbI033.jpg?source=d16d100b

?

對(duì)于其中的函數(shù)命名基本都是自明的,主要的差別在于:對(duì)于雙下劃線開(kāi)頭的函數(shù)(__get_free_page, __free_page等)返回值或者參數(shù)為struct page *,而其他的函數(shù)返回值為unsigned long,即線性地址地址。

3、內(nèi)核中不連續(xù)頁(yè)的分配

根據(jù)上文的講述,我們知道物理上連續(xù)的映射對(duì)內(nèi)核是最好的,但并不是總能成功的使用。所以?xún)?nèi)核提供了類(lèi)似用戶(hù)空間訪問(wèn)內(nèi)存一樣的機(jī)制(vmalloc)來(lái)進(jìn)行對(duì)內(nèi)核中不連續(xù)頁(yè)的分配。這一部分就是上文中所說(shuō)的vmalloc區(qū)域。這部分主要是一個(gè)vmalloc函數(shù):

 void *vmalloc(unsigned long size);

在該函數(shù)的實(shí)現(xiàn)過(guò)程中,需要先申請(qǐng)一部分虛擬內(nèi)存空間vm_area,然后將這部分空間映射到vmalloc區(qū)域中。對(duì)于映射的物理內(nèi)存,內(nèi)核更傾向于使用高地址空間(ZONE_HIGHMEM),來(lái)節(jié)省寶貴的地地址空間。對(duì)于不同vmalloc調(diào)用申請(qǐng)的vm_area之間,會(huì)有一個(gè)hole來(lái)隔離,以避免越界訪問(wèn)。


pYYBAGJ7h8uAZfKQAABjVlY6VMI002.jpg?source=d16d100b

?

注意vmalloc系統(tǒng)底層也是使用伙伴系統(tǒng)來(lái)分配內(nèi)存,所以申請(qǐng)內(nèi)存的大小只能是整頁(yè)的(頁(yè)大小對(duì)齊)。

在這部分有一個(gè)有意思的事情:vmalloc區(qū)域在IA-32中預(yù)設(shè)的大小是128MB,這部分內(nèi)存一般會(huì)被內(nèi)核模塊使用。vmalloc區(qū)域的大小是可以定制的,在新版內(nèi)核中可以在內(nèi)核啟動(dòng)選項(xiàng)中加入vmalloc=xxxMB的方式來(lái)修改,或者修改內(nèi)核代碼對(duì)應(yīng)的宏:

unsigned int __VMALLOC_RESERVE = 128 << 20;

如果修改了vmalloc區(qū)域的大小,那么內(nèi)核能夠直接映射的區(qū)域?qū)?huì)縮小,即kmalloc能夠使用的內(nèi)存將會(huì)變少(kmalloc使用slab allocator分配,后文將會(huì)介紹),但是內(nèi)核真正使用的物理內(nèi)存和vmalloc區(qū)域的大小沒(méi)有直接關(guān)系。所以在內(nèi)核模塊的編寫(xiě)過(guò)程中,要根據(jù)需求來(lái)使用vmalloc和kmalloc,而了解他們的內(nèi)存分配機(jī)制是很有好處的。

4、內(nèi)核映射

盡管vmalloc函數(shù)族可用于從高端內(nèi)存向內(nèi)核映射頁(yè)框,但這并不是這些函數(shù)的實(shí)際用途。內(nèi)核提供了其他函數(shù)用于將ZONE_HIGHMEM頁(yè)框顯式的映射到內(nèi)核空間。

如果需要長(zhǎng)期的將高端頁(yè)框映射到內(nèi)核地址空間中,即持久映射,需要使用kmap函數(shù),映射的空間指向上文圖中所指Persistent Mapings。內(nèi)核使用kunmap接觸映射。持久映射kmap函數(shù)不能用于處理中斷處理程序,因?yàn)閗map過(guò)程可能進(jìn)入睡眠狀態(tài)。

為了能夠原子的執(zhí)行映射過(guò)程(邏輯上稱(chēng)為kmap_atomic),內(nèi)核提供了臨時(shí)映射機(jī)制,也被稱(chēng)作固定映射,頁(yè)面也會(huì)被映射到Fixmaps區(qū)域。映射的API分別是kmap_atomic和kunmap_atomic。固定映射可以用在中斷處理程序中。

對(duì)于不支持高端內(nèi)存的體系結(jié)構(gòu)(如64位體系結(jié)構(gòu)),則將以上若干映射函數(shù)通過(guò)預(yù)編譯選項(xiàng)指向了對(duì)應(yīng)的兼容函數(shù)。事實(shí)上對(duì)于這些體系結(jié)構(gòu)的映射,都是簡(jiǎn)單的返回對(duì)應(yīng)的內(nèi)存地址即可,因?yàn)閮?nèi)核可以在直接映射區(qū)域簡(jiǎn)單的找到對(duì)應(yīng)的地址。

六、slab分配器

上面所描述的物理內(nèi)存管理機(jī)制中,最小粒度的內(nèi)存管理單元是頁(yè)框,大小一般是4KB,而在內(nèi)存中無(wú)論何時(shí)申請(qǐng)內(nèi)存都分配一個(gè)頁(yè)面是不合適的方式,所以引入了新的管理機(jī)制,即slab分配器。Slab是Sun公司的一個(gè)雇員Jeff Bonwick在Solaris 2.4中設(shè)計(jì)并實(shí)現(xiàn)的。slab分配器將大小相同的內(nèi)核對(duì)象放在一起,當(dāng)對(duì)象被free了之后并不是直接還給伙伴系統(tǒng),而是將這部分對(duì)象的頁(yè)面保存下來(lái),在下一次該類(lèi)對(duì)象的內(nèi)存申請(qǐng)時(shí)分配給新的對(duì)象。這種機(jī)制的優(yōu)勢(shì)在于:1、能夠按照CPU緩存的大小來(lái)組織分配對(duì)象的位置,一般來(lái)說(shuō),都會(huì)將若干個(gè)相同的對(duì)象放在一個(gè)cacheline中,并且對(duì)象占用的內(nèi)存不會(huì)跨越兩個(gè)cacheline。這樣的設(shè)計(jì)能夠保證slab分配器分配的對(duì)象能夠較多時(shí)間的存在于CPU緩存中。2、采用LIFO方式管理對(duì)象。這種做法基于:最近釋放的對(duì)象空間是最有可能存在于cache中的。這也能夠有效的利用cache。

各個(gè)緩存管理的對(duì)象,會(huì)合并為較大的組,覆蓋一個(gè)或者多個(gè)連續(xù)的頁(yè)框。這種組稱(chēng)作slab,每個(gè)緩存由幾個(gè)這種slab組成。這也是slab分配器命名的由來(lái)。

1、slab、slob、slub分配器

Linux內(nèi)核中目前支持三種分配器,其中slab前文已經(jīng)簡(jiǎn)單介紹過(guò)了,另外兩種分配器是備選分配器,可以在內(nèi)核編譯選項(xiàng)中指定。由于對(duì)上層提供的API是固定的,僅僅是底層實(shí)現(xiàn)不同,所以Kernel開(kāi)發(fā)者不必去考慮底層的分配情況。

slab分配器雖然有很大的優(yōu)勢(shì),但是其存在兩個(gè)問(wèn)題:1、在較小的內(nèi)存系統(tǒng)下,slab分配器過(guò)于復(fù)雜。如嵌入式環(huán)境下slab顯得有些過(guò)于龐大。2、在內(nèi)存很大的巨型機(jī)上,slab分配器本身的數(shù)據(jù)結(jié)構(gòu)所占用的內(nèi)存空間過(guò)大,最大的可高達(dá)2GB以上。

對(duì)于前一種情況,設(shè)計(jì)了slob分配器,它圍繞一個(gè)simple linked list of block展開(kāi)(也是slob的由來(lái)),在分配內(nèi)存的時(shí)候,采用了最先適配算法(first-fit)。

對(duì)于后一種情況,設(shè)計(jì)了slub分配器,slub分配器將頁(yè)框打包為組,并通過(guò)struct page中未使用的字段來(lái)管理這些組,試圖最小化內(nèi)存開(kāi)銷(xiāo)。slub分配器事實(shí)上是基于slab分配器的一種優(yōu)化結(jié)構(gòu)。在大型機(jī)上slub分配器上有著更好的性能。

2、slab分配器的原理

內(nèi)核中一般的內(nèi)存分配和釋放的函數(shù)有kmalloc、kzalloc、kcalloc。這三個(gè)函數(shù)的區(qū)別是:kmalloc僅僅申請(qǐng)一片空間,kzalloc在申請(qǐng)一篇空間之后將其置0。kcalloc很少用,即對(duì)數(shù)組進(jìn)行空間分配并置0。

所有活動(dòng)的slab緩存可以通過(guò)cat /proc/slabinfo來(lái)看到。

slab分配器由一個(gè)緊密交織的數(shù)據(jù)和內(nèi)存結(jié)構(gòu)的網(wǎng)絡(luò)組成,主要可以分為如圖的兩部分:保存管理型數(shù)據(jù)的緩存對(duì)象和保存被管理對(duì)象的各個(gè)slab。


poYBAGJ7h8uAK6uAAAA0zFW6GJI616.jpg?source=d16d100b

?

每個(gè)slab緩存只負(fù)責(zé)一種對(duì)象類(lèi)型,或者提供一般性的緩沖區(qū)。下圖中給出了緩存的精細(xì)結(jié)構(gòu):


pYYBAGJ7h8uAZCu1AABizruwUwI393.jpg?source=d16d100b

?

可以看到對(duì)于每個(gè)slab緩存,都會(huì)保存成一個(gè)struct kmem_cache,每個(gè)結(jié)構(gòu)里面包含一個(gè)穿在一起的鏈表,以及三個(gè)鏈表頭:free、partial、full,分別表示空閑鏈、部分空閑鏈和滿(mǎn)鏈。含義和字面意思相同。對(duì)象在slab中并不是連續(xù)排列的,用戶(hù)可以要求對(duì)象按硬件緩存對(duì)齊,也可以要求按照BYTES_PER_WORD對(duì)齊,該值表示void指針?biāo)璧淖止?jié)的數(shù)目。

創(chuàng)建新的slab緩存需要調(diào)用kmem_cache_create函數(shù),返回struct kmem_cache結(jié)構(gòu)。創(chuàng)建緩存的時(shí)候需要制定緩存的可讀name(會(huì)出現(xiàn)在/proc/slabinfo中),還需要制定被管理對(duì)象以字節(jié)計(jì)的長(zhǎng)度(size),在對(duì)齊數(shù)據(jù)時(shí)使用的偏移量(align),以及flags標(biāo)志。另外還需要制定構(gòu)造/析構(gòu)函數(shù)ctor/dtor。

分配對(duì)象時(shí)調(diào)用kmem_cache_alloc,函數(shù)需要指定創(chuàng)建過(guò)的slab緩存,以及flags。內(nèi)核支持的所有GFP_xxx宏都可以用于指定標(biāo)志。

下圖顯示了分配對(duì)象的過(guò)程:


poYBAGJ7h8uAKzrvAAB-dHvi8iI358.jpg?source=d16d100b

?

3、通用緩存

如果不涉及對(duì)象緩存,而是傳統(tǒng)意義上的分配/釋放內(nèi)存,則需要調(diào)用kmalloc和kfree函數(shù),而這兩個(gè)函數(shù)的后端依然是使用slab分配器進(jìn)行分配的。kmalloc的基礎(chǔ)是一個(gè)數(shù)組,其中是一些分別用于不同內(nèi)存長(zhǎng)度的slab緩存,數(shù)組項(xiàng)是cache_sizes的實(shí)例。該數(shù)據(jù)結(jié)構(gòu)定義如下:


 
struct cache_sizes {
    size_t cs_size;
    kmem_cache_t *cs_cachep;
    kmem_cache_t *cs_dmacachep;
#ifdef CONFIG_ZONE_DMA
    struct kmem_cache *cs_dmacachep;
#endif
}

cs_size指定了該項(xiàng)負(fù)責(zé)的內(nèi)存區(qū)的長(zhǎng)度。每個(gè)長(zhǎng)度對(duì)應(yīng)兩個(gè)slab緩存,其中之一提供適合DMA訪問(wèn)的內(nèi)存。通過(guò)cat /proc/slabinfo中能夠看到,kmalloc-xxx和dma-kmalloc-xxx就是這一部分提供的。

kmalloc定義在,該函數(shù)首先檢查所需的緩存是否用常數(shù)來(lái)指定,如果是這種情況,所需的緩存可以在編譯時(shí)靜態(tài)確定,這可以提高速度(內(nèi)核的優(yōu)化真是無(wú)所不用其極!?。?。否則,該函數(shù)調(diào)用__kmalloc查找長(zhǎng)度匹配的緩存,后者是__do_kmalloc的前端,提供參數(shù)轉(zhuǎn)換功能。

mm/slab.c
 
void *__do_kmalloc(size_t size, gfp_t flags)
{
    kmem_cache_t *cachep;
    cachep = __find_general_cachep(size, flags);
    if (unlikely(ZERO_OR_NULL_PTR(cachep)))
        return NULL;
    return __cache_alloc(cachep, flags);
}

__find_general_cachep在上文提到的緩存中找到適當(dāng)?shù)囊粋€(gè),之后使用__cache_alloc函數(shù)完成最終的分配。

七、處理器高速緩存和TLB控制

在這里簡(jiǎn)單的總結(jié)一些Kernel中和TLB/高速緩存相關(guān)的函數(shù),具體TLB的實(shí)現(xiàn)機(jī)制與體系架構(gòu)相關(guān)性很大,就不詳細(xì)總結(jié)了。

flush_tlb_all和flush_cache_all刷出整個(gè)TLB/高速緩存。此操作只在操縱內(nèi)核頁(yè)表時(shí)需要,因?yàn)榇祟?lèi)修改不僅影響所有進(jìn)程,而且影響系統(tǒng)中的所有處理器。

flush_tlb_mm(struct mm_struct *mm)和flush_cache_mm刷出所有屬于地址空間mm的TLB/高速緩存項(xiàng)。

flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)和flush_cache_range(vma, start, end)刷出地址范圍vma->vm_mm中虛擬地址start和end之間的所有TLB/高速緩存項(xiàng)。

flush_tlb_page(struct vm_area_struct *vma, unsigned long page) 和flush_cache_page(vma, page)刷出虛擬地址在[page, page + PAGE_SIZE]范圍內(nèi)所有的TLB/高速緩存項(xiàng)。

update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)在處理頁(yè)失效之后調(diào)用。它在處理器的內(nèi)存管理單元MMU中加入信息,是的虛擬地址address由頁(yè)表項(xiàng)pte描述。僅當(dāng)存在外部MMU時(shí)才需要該函數(shù),通常MMU集成在處理器內(nèi)部。

此外,flush_cache_和flush_tlb_函數(shù)常常成對(duì)出現(xiàn),例如,在使用fork進(jìn)程復(fù)制進(jìn)程的地址空間時(shí),則:1、刷出高速緩存,2、操作內(nèi)存,3、刷出TLB。這個(gè)順序很重要,因?yàn)?/p>

如果順序相反,那么在TLB刷出之后,正確信息提供之前,多處理器系統(tǒng)中的另一個(gè)CPU可能從進(jìn)程的頁(yè)表項(xiàng)取得錯(cuò)誤的信息。

在刷出高速緩存時(shí),某些體系結(jié)構(gòu)需要依賴(lài)TLB中的“虛擬->物理”轉(zhuǎn)換規(guī)則。flush_tlb_mm必須在flush_cache_mm之后執(zhí)行以確保這一點(diǎn)。

小結(jié)

這部分東西實(shí)在是太多,簡(jiǎn)單的總結(jié)一下就已經(jīng)這么多了。在這里對(duì)以上的內(nèi)容進(jìn)行一個(gè)簡(jiǎn)單的概括。

在內(nèi)核進(jìn)入正常運(yùn)行之后,內(nèi)存管理分為兩個(gè)層次:伙伴系統(tǒng)負(fù)責(zé)物理頁(yè)框的管理。在伙伴系統(tǒng)之上,所有的內(nèi)存管理都基于此,主要分為:slab分配器處理小塊內(nèi)存;vmalloc模塊為不連續(xù)物理頁(yè)框提供映射;永久映射區(qū)域和固定映射區(qū)域提供對(duì)高地址物理頁(yè)框的訪問(wèn)。

內(nèi)存管理的初始化很具有挑戰(zhàn)性,內(nèi)核通過(guò)引入一個(gè)非常簡(jiǎn)單的自舉內(nèi)存分配器(bootmem)解決了該問(wèn)題,該分配器在正式的分配機(jī)制(伙伴系統(tǒng))啟用后停用。

審核編輯:符乾江

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11407

    瀏覽量

    212126
  • 文件系統(tǒng)
    +關(guān)注

    關(guān)注

    0

    文章

    293

    瀏覽量

    20197
  • 內(nèi)存管理
    +關(guān)注

    關(guān)注

    0

    文章

    168

    瀏覽量

    14399
  • 虛擬內(nèi)存
    +關(guān)注

    關(guān)注

    0

    文章

    77

    瀏覽量

    8176
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Linux kernel內(nèi)存管理模塊結(jié)構(gòu)分析

    基于上面章節(jié)的需求,Linux kernel從虛擬內(nèi)存(VM)、DMA mapping以及DMA buffer sharing三個(gè)角度,對(duì)內(nèi)存進(jìn)行管理.
    發(fā)表于 09-19 11:55 ?1982次閱讀
    <b class='flag-5'>Linux</b> kernel<b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理</b>模塊結(jié)構(gòu)分析

    深度解析Linux內(nèi)存管理體系

    Linux內(nèi)存管理的整體模式是虛擬內(nèi)存管理(分頁(yè)內(nèi)存管理
    發(fā)表于 08-06 16:55 ?1922次閱讀

    走進(jìn)Linux內(nèi)存系統(tǒng)探尋內(nèi)存管理的機(jī)制和奧秘

    Linux 內(nèi)存是后臺(tái)開(kāi)發(fā)人員,需要深入了解的計(jì)算機(jī)資源。合理的使用內(nèi)存,有助于提升機(jī)器的性能和穩(wěn)定性。本文主要介紹Linux 內(nèi)存組織結(jié)構(gòu)
    的頭像 發(fā)表于 01-05 09:47 ?1803次閱讀

    關(guān)于Linux內(nèi)存管理的詳細(xì)介紹

    Linux內(nèi)存管理是指對(duì)系統(tǒng)內(nèi)存的分配、釋放、映射、管理、交換、壓縮等一系列操作的管理。在
    發(fā)表于 03-06 09:28 ?1136次閱讀

    Linux內(nèi)核的內(nèi)存管理詳解

    內(nèi)存管理的主要工作就是對(duì)物理內(nèi)存進(jìn)行組織,然后對(duì)物理內(nèi)存的分配和回收。但是Linux引入了虛擬地址的概念。
    發(fā)表于 08-31 14:46 ?929次閱讀
    <b class='flag-5'>Linux</b>內(nèi)核的<b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理</b><b class='flag-5'>詳解</b>

    Linux內(nèi)核內(nèi)存管理架構(gòu)解析

    內(nèi)存管理子系統(tǒng)可能是linux內(nèi)核中最為復(fù)雜的一個(gè)子系統(tǒng),其支持的功能需求眾多,如頁(yè)面映射、頁(yè)面分配、頁(yè)面回收、頁(yè)面交換、冷熱頁(yè)面、緊急頁(yè)面、頁(yè)面碎片管理、頁(yè)面緩存、頁(yè)面統(tǒng)計(jì)等,而且對(duì)
    的頭像 發(fā)表于 01-04 09:24 ?838次閱讀
    <b class='flag-5'>Linux</b>內(nèi)核<b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理</b>架構(gòu)解析

    linux內(nèi)存管理

    公交,地鐵,睡前必備,方便大家查閱,持續(xù)更新,敬請(qǐng)期待!---更新于2020-02-12linux 內(nèi)存管理Linux內(nèi)存初始化CPU是
    發(fā)表于 07-22 08:41

    linux內(nèi)存管理機(jī)制淺析

    本內(nèi)容介紹了arm linux內(nèi)存管理機(jī)制,詳細(xì)說(shuō)明了linux內(nèi)核內(nèi)存管理,
    發(fā)表于 12-19 14:09 ?73次下載
    <b class='flag-5'>linux</b><b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理</b>機(jī)制淺析

    linux內(nèi)存管理

    linux內(nèi)存管理
    發(fā)表于 10-24 11:12 ?3次下載
    <b class='flag-5'>linux</b><b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理</b>

    你知道linux內(nèi)存管理基礎(chǔ)及方法?

    linux內(nèi)存管理采取的分頁(yè)存取機(jī)制,會(huì)將內(nèi)存中不經(jīng)常使用的數(shù)據(jù)塊交換到虛擬內(nèi)存中。linux
    發(fā)表于 04-28 17:12 ?1265次閱讀

    適當(dāng)了解Linux內(nèi)存管理等問(wèn)題

    linux內(nèi)存管理還是比較復(fù)雜的,其中牽扯到很多方面的知識(shí),這篇小博文算是自己對(duì)于內(nèi)存管理的一點(diǎn)點(diǎn)的總結(jié)
    發(fā)表于 05-13 10:10 ?610次閱讀
    適當(dāng)了解<b class='flag-5'>Linux</b><b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理</b>等問(wèn)題

    嵌入式 Linux 中的內(nèi)存管理

    點(diǎn)擊 嵌入式 Linux 中的內(nèi)存管理
    發(fā)表于 11-02 10:36 ?12次下載
    嵌入式 <b class='flag-5'>Linux</b> 中的<b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理</b>

    Linux內(nèi)存管理的基礎(chǔ)知識(shí)科普

    Linux內(nèi)存管理可謂是學(xué)好Linux的必經(jīng)之路,也是Linux的關(guān)鍵知識(shí)點(diǎn),有人說(shuō)打通了內(nèi)存
    的頭像 發(fā)表于 06-08 15:24 ?2279次閱讀

    Linux內(nèi)存管理體系介紹

    內(nèi)存是計(jì)算機(jī)最重要的資源之一,內(nèi)存管理是操作系統(tǒng)最重要的任務(wù)之一。內(nèi)存管理并不是簡(jiǎn)單地管理一下
    的頭像 發(fā)表于 08-08 09:28 ?1845次閱讀

    Linux 內(nèi)存管理總結(jié)

    一、Linux內(nèi)存管理概述 Linux內(nèi)存管理是指對(duì)系統(tǒng)內(nèi)存
    的頭像 發(fā)表于 11-10 14:58 ?669次閱讀
    <b class='flag-5'>Linux</b> <b class='flag-5'>內(nèi)存</b><b class='flag-5'>管理</b>總結(jié)
    主站蜘蛛池模板: 奇米色吧 | 日韩在线一区视频 | 2018天天操天天干 | 在线黄色大片 | 午夜资源| 成人影院在线观看视频 | 夜夜穞狠狠穞 | 丁香激情六月 | 国产h在线播放 | 毛片快播| 天天看天天操 | 中文字幕亚洲一区二区v@在线 | 国产成人精品视频一区二区不卡 | 美女被异性狂揉下部羞羞视频 | 四虎国产精品永久地址49 | 港台无码 | 就要干就要操 | 免费视频爰爱太爽了 | 色五月激情五月 | 欧美性猛交xxxx乱大交中文 | 精品国产一二三区 | 婷婷色网 | 天天插天天爱 | 日本边添边爱边摸边做边爱 | 性欧美巨大 | 成 黄 色 激 情视频网站 | 就操成人网 | 久久久噜久噜久久gif动图 | 欧美日韩精品一区二区在线线 | 在线电影天堂 | 五月婷婷色丁香 | 在线看欧美成人中文字幕视频 | 夜夜春色 | 久久夜色精品国产亚洲 | 99r8这里精品热视频免费看 | 天天操2023| 久久久久国产精品免费免费 | 国产欧美日韩综合精品一区二区 | 特黄特黄视频 | 黄色网免费| 五月婷婷一区二区 |