Linux內存管理中的slab分配器


轉載自:http://edsionte.com/techblog/archives/4019

 

Linux內核中基於伙伴算法實現的分區頁框分配器適合大塊內存的請求,它所分配的內存區是以頁框為基本單位的。對於內核中小塊連續內存的請求,比 如說幾個字節或者幾百個字節,如果依然分配一個頁框來來滿足該請求,那么這很明顯就是一種浪費,即產生內部碎片(internal fragmentation)

為了解決小塊內存的分配,Linux內核基於Solaris 2.4中的slab分配算法實現了自己的slab分配器。除此之外,slab分配器另一個主要功能是作為一個高速緩存,它用來存儲內核中那些經常分配並釋放的對象。

1.slab分配器的基本原理

slab分配器中用到了對象這個概念,所謂對象就是內核中的數據結構以及對該數據結構進行創建和撤銷的操作。它的基本思想是將內核中經常使用的對象 放到高速緩存中,並且由系統保持為初始的可利用狀態。比如進程描述符,內核中會頻繁對此數據進行申請和釋放。當一個新進程創建時,內核會直接從slab分 配器的高速緩存中獲取一個已經初始化了的對象;當進程結束時,該結構所占的頁框並不被釋放,而是重新返回slab分配器中。如果沒有基於對象的slab分 配器,內核將花費更多的時間去分配、初始化以及釋放一個對象。

slab分配器有以下三個基本目標:

1.減少伙伴算法在分配小塊連續內存時所產生的內部碎片;

2.將頻繁使用的對象緩存起來,減少分配、初始化和釋放對象的時間開銷。

3.通過着色技術調整對象以更好的使用硬件高速緩存;

2.slab分配器的結構

slab分配器為每種對象分配一個高速緩存,這個緩存可以看做是同類型對象的一種儲備。每個高速緩存所占的內存區又被划分多個slab,每個 slab是由一個或多個連續的頁框組成。每個頁框中包含若干個對象,既有已經分配的對象,也包含空閑的對象。slab分配器的大致組成圖如下:

每個高速緩存通過kmem_cache結構來描述,這個結構中包含了對當前高速緩存各種屬性信息的描述。所有的高速緩存通過雙鏈表組織在一起,形成 高速緩存鏈表cache_chain。每個kmem_cache結構中並不包含對具體slab的描述,而是通過kmem_list3結構組織各個 slab。該結構的定義如下:

1 struct kmem_list3 {
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;
8         spinlock_t list_lock;
9         struct array_cache *shared;
10         struct array_cache **alien;
11         unsigned long next_reap;
12         int free_touched;
13 };

可以看到,該結構將當前緩存中的所有slab分為三個集合:空閑對象的slab鏈表slabs_free,非空閑對象的slab鏈表 slabs_full以及部分空閑對象的slab鏈表slabs_partial。每個slab有相應的slab描述符,即slab結構,它的定義如下:

1 struct slab {
2         struct list_head list;
3         unsigned long colouroff;
4         void *s_mem;
5         unsigned int inuse;
6         kmem_bufctl_t free;
7         unsigned short nodeid;
8 };

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 = {
2         .batchcount = 1,
3         .limit = BOOT_CPUCACHE_ENTRIES,
4         .shared = 1,
5         .buffer_size = sizeof(struct kmem_cache),
6         .name = "kmem_cache",
7 };

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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM