轉載自:http://edsionte.com/techblog/archives/4019node
Linux內核中基於夥伴算法實現的分區頁框分配器適合大塊內存的請求,它所分配的內存區是以頁框爲基本單位的。對於內核中小塊連續內存的請求,比 如說幾個字節或者幾百個字節,若是依然分配一個頁框來來知足該請求,那麼這很明顯就是一種浪費,即產生內部碎片(internal fragmentation)算法
爲了解決小塊內存的分配,Linux內核基於Solaris 2.4中的slab分配算法實現了本身的slab分配器。除此以外,slab分配器另外一個主要功能是做爲一個高速緩存,它用來存儲內核中那些常常分配並釋放的對象。緩存
1.slab分配器的基本原理
slab分配器中用到了對象這個概念,所謂對象就是內核中的數據結構以及對該數據結構進行建立和撤銷的操做。它的基本思想是將內核中常常使用的對象 放到高速緩存中,而且由系統保持爲初始的可利用狀態。好比進程描述符,內核中會頻繁對此數據進行申請和釋放。當一個新進程建立時,內核會直接從slab分 配器的高速緩存中獲取一個已經初始化了的對象;當進程結束時,該結構所佔的頁框並不被釋放,而是從新返回slab分配器中。若是沒有基於對象的slab分 配器,內核將花費更多的時間去分配、初始化以及釋放一個對象。數據結構
slab分配器有如下三個基本目標:spa
1.減小夥伴算法在分配小塊連續內存時所產生的內部碎片;3d
2.將頻繁使用的對象緩存起來,減小分配、初始化和釋放對象的時間開銷。code
3.經過着色技術調整對象以更好的使用硬件高速緩存;對象
2.slab分配器的結構
slab分配器爲每種對象分配一個高速緩存,這個緩存能夠看作是同類型對象的一種儲備。每一個高速緩存所佔的內存區又被劃分多個slab,每一個 slab是由一個或多個連續的頁框組成。每一個頁框中包含若干個對象,既有已經分配的對象,也包含空閒的對象。slab分配器的大體組成圖以下:blog

每一個高速緩存經過kmem_cache結構來描述,這個結構中包含了對當前高速緩存各類屬性信息的描述。全部的高速緩存經過雙鏈表組織在一塊兒,造成 高速緩存鏈表cache_chain。每一個kmem_cache結構中並不包含對具體slab的描述,而是經過kmem_list3結構組織各個 slab。該結構的定義以下:接口
2 |
struct list_head slabs_partial; |
3 |
struct list_head slabs_full; |
4 |
struct list_head slabs_free; |
5 |
unsigned long free_objects; |
6 |
unsigned int free_limit; |
7 |
unsigned int colour_next; |
9 |
struct array_cache *shared; |
10 |
struct array_cache **alien; |
11 |
unsigned long next_reap; |
能夠看到,該結構將當前緩存中的全部slab分爲三個集合:空閒對象的slab鏈表slabs_free,非空閒對象的slab鏈表 slabs_full以及部分空閒對象的slab鏈表slabs_partial。每一個slab有相應的slab描述符,即slab結構,它的定義以下:
3 |
unsigned long colouroff; |
slab描述符中的list字段標明瞭當前slab處於三個slab鏈表的其中一個。咱們將上述的slab分配器進行細化,能夠獲得下面的結構圖:

3.高速緩存的分類
slab高速緩存分爲兩大類,普通高速緩存和專用高速緩存。普通高速緩存並不針對內核中特定的對象,它首先會爲kmem_cache結構自己提供高 速緩存,這類緩存保存在cache_cache變量中,該變量即表明的是cache_chain鏈表中的第一個元素;另外一方面,它爲內核提供了一種通用高 速緩存。專用高速緩存是根據內核所需,經過指定具體的對象而建立。
3.1 普通高速緩存
slab分配器中kmem_cache是用來描述高速緩存的結構,所以它自己也須要slab分配器對其進行高速緩存。cache_cache變量保存着對高速緩存描述符的高速緩存。
1 |
static struct kmem_cache cache_cache = { |
3 |
.limit = BOOT_CPUCACHE_ENTRIES, |
5 |
.buffer_size = sizeof ( struct kmem_cache), |
slab分配器所提供的小塊連續內存的分配是經過通用高速緩存實現的。通用高速緩存所提供的對象具備幾何分佈的大小,範圍爲32到131072字節。內核中提供了kmalloc()和kfree()兩個接口分別進行內存的申請和釋放。
3.2 專用高速緩存
內核爲專用高速緩存的申請和釋放提供了一套完整的接口,根據所傳入的參數爲具體的對象分配slab緩存。
高速緩存的申請和釋放
kmem_cache_create()用於對一個指定的對象建立高速緩存。它從cache_cache普通高速緩存中爲新的專有緩存分配一個高速 緩存描述符,並把這個描述符插入到高速緩存描述符造成的cache_chain鏈表中。kmem_cache_destory()用於撤銷一個高速緩存, 並將它從cache_chain鏈表上刪除。
slab的申請和釋放
kmem_cache_alloc()在其參數所指定的高速緩存中分配一個slab。相反,kmem_cache_free()在其參數所指定的高速緩存中釋放一個slab。