一文帶你玩轉(zhuǎn)Linux內(nèi)存管理中的slab分配器?。ê曨l解析)
Linux內(nèi)核中基于伙伴算法實(shí)現(xiàn)的分區(qū)頁框分配器適合大塊內(nèi)存的請(qǐng)求,它所分配的內(nèi)存區(qū)是以頁框?yàn)榛締挝坏摹?duì)于內(nèi)核中小塊連續(xù)內(nèi)存的請(qǐng)求,比 如說幾個(gè)字節(jié)或者幾百個(gè)字節(jié),如果依然分配一個(gè)頁框來來滿足該請(qǐng)求,那么這很明顯就是一種浪費(fèi),即產(chǎn)生內(nèi)部碎片(internal fragmentation)
為了解決小塊內(nèi)存的分配,Linux內(nèi)核基于Solaris 2.4中的slab分配算法實(shí)現(xiàn)了自己的slab分配器。除此之外,slab分配器另一個(gè)主要功能是作為一個(gè)高速緩存,它用來存儲(chǔ)內(nèi)核中那些經(jīng)常分配并釋放的對(duì)象。
1.slab分配器的基本原理
slab分配器中用到了對(duì)象這個(gè)概念,所謂對(duì)象就是內(nèi)核中的數(shù)據(jù)結(jié)構(gòu)以及對(duì)該數(shù)據(jù)結(jié)構(gòu)進(jìn)行創(chuàng)建和撤銷的操作。它的基本思想是將內(nèi)核中經(jīng)常使用的對(duì)象 放到高速緩存中,并且由系統(tǒng)保持為初始的可利用狀態(tài)。比如進(jìn)程描述符,內(nèi)核中會(huì)頻繁對(duì)此數(shù)據(jù)進(jìn)行申請(qǐng)和釋放。當(dāng)一個(gè)新進(jìn)程創(chuàng)建時(shí),內(nèi)核會(huì)直接從slab分 配器的高速緩存中獲取一個(gè)已經(jīng)初始化了的對(duì)象;當(dāng)進(jìn)程結(jié)束時(shí),該結(jié)構(gòu)所占的頁框并不被釋放,而是重新返回slab分配器中。如果沒有基于對(duì)象的slab分 配器,內(nèi)核將花費(fèi)更多的時(shí)間去分配、初始化以及釋放一個(gè)對(duì)象。
slab分配器有以下三個(gè)基本目標(biāo):
減少伙伴算法在分配小塊連續(xù)內(nèi)存時(shí)所產(chǎn)生的內(nèi)部碎片;
將頻繁使用的對(duì)象緩存起來,減少分配、初始化和釋放對(duì)象的時(shí)間開銷。
通過著色技術(shù)調(diào)整對(duì)象以更好的使用硬件高速緩存;
【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。∏?00名進(jìn)群領(lǐng)取,額外贈(zèng)送一份價(jià)值699的內(nèi)核資料包(含視頻教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ??


?
2.slab分配器的結(jié)構(gòu)
slab分配器為每種對(duì)象分配一個(gè)高速緩存,這個(gè)緩存可以看做是同類型對(duì)象的一種儲(chǔ)備。每個(gè)高速緩存所占的內(nèi)存區(qū)又被劃分多個(gè)slab,每個(gè) slab是由一個(gè)或多個(gè)連續(xù)的頁框組成。每個(gè)頁框中包含若干個(gè)對(duì)象,既有已經(jīng)分配的對(duì)象,也包含空閑的對(duì)象。slab分配器的大致組成圖如下:

每個(gè)高速緩存通過kmem_cache結(jié)構(gòu)來描述,這個(gè)結(jié)構(gòu)中包含了對(duì)當(dāng)前高速緩存各種屬性信息的描述。所有的高速緩存通過雙鏈表組織在一起,形成 高速緩存鏈表cache_chain。每個(gè)kmem_cache結(jié)構(gòu)中并不包含對(duì)具體slab的描述,而是通過kmem_list3結(jié)構(gòu)組織各個(gè) slab。該結(jié)構(gòu)的定義如下:
可以看到,該結(jié)構(gòu)將當(dāng)前緩存中的所有slab分為三個(gè)集合:空閑對(duì)象的slab鏈表slabs_free,非空閑對(duì)象的slab鏈表 slabs_full以及部分空閑對(duì)象的slab鏈表slabs_partial。每個(gè)slab有相應(yīng)的slab描述符,即slab結(jié)構(gòu),它的定義如下:
slab描述符中的list字段標(biāo)明了當(dāng)前slab處于三個(gè)slab鏈表的其中一個(gè)。我們將上述的slab分配器進(jìn)行細(xì)化,可以得到下面的結(jié)構(gòu)圖:

3.高速緩存的分類
slab高速緩存分為兩大類,普通高速緩存和專用高速緩存。普通高速緩存并不針對(duì)內(nèi)核中特定的對(duì)象,它首先會(huì)為kmem_cache結(jié)構(gòu)本身提供高 速緩存,這類緩存保存在cache_cache變量中,該變量即代表的是cache_chain鏈表中的第一個(gè)元素;另一方面,它為內(nèi)核提供了一種通用高 速緩存。專用高速緩存是根據(jù)內(nèi)核所需,通過指定具體的對(duì)象而創(chuàng)建。
3.1 普通高速緩存
slab分配器中kmem_cache是用來描述高速緩存的結(jié)構(gòu),因此它本身也需要slab分配器對(duì)其進(jìn)行高速緩存。cache_cache變量保存著對(duì)高速緩存描述符的高速緩存。
slab分配器所提供的小塊連續(xù)內(nèi)存的分配是通過通用高速緩存實(shí)現(xiàn)的。通用高速緩存所提供的對(duì)象具有幾何分布的大小,范圍為32到131072字節(jié)。內(nèi)核中提供了kmalloc()和kfree()兩個(gè)接口分別進(jìn)行內(nèi)存的申請(qǐng)和釋放。
3.2 專用高速緩存
內(nèi)核為專用高速緩存的申請(qǐng)和釋放提供了一套完整的接口,根據(jù)所傳入的參數(shù)為具體的對(duì)象分配slab緩存。
高速緩存的申請(qǐng)和釋放
kmem_cache_create()用于對(duì)一個(gè)指定的對(duì)象創(chuàng)建高速緩存。它從cache_cache普通高速緩存中為新的專有緩存分配一個(gè)高速 緩存描述符,并把這個(gè)描述符插入到高速緩存描述符形成的cache_chain鏈表中。kmem_cache_destory()用于撤銷一個(gè)高速緩存, 并將它從cache_chain鏈表上刪除。
slab的申請(qǐng)和釋放
kmem_cache_alloc()在其參數(shù)所指定的高速緩存中分配一個(gè)slab。相反,kmem_cache_free()在其參數(shù)所指定的高速緩存中釋放一個(gè)slab。
