12.29 linux 內核 內存管理 slub算法 (一) 原理

內核管理頁面使用了2個算法:夥伴算法和slub算法,夥伴算法以頁為單位管理內存,但在大多數情況下,程序需要的並不是一整頁,而是幾個、幾十個字節的小內存。於是需要另外一套系統來完成對小內存的管理,這就是slub系統。slub系統運行在夥伴系統之上,為內核提供小內存管理的功能。

slub把內存分組管理,每個組分別包含2^3、2^4、...2^11個字節,在4K頁大小的默認情況下,另外還有兩個特殊的組,分別是96B和192B,共11組。之所以這樣分配是因為如果申請2^12B大小的內存,就可以使用夥伴系統提供的接口直接申請一個完整的頁面即可。

slub就相當於零售商,它向夥伴系統“批發”內存,然後在零售出去。一下是整個slub系統的框圖:

linux 內核 內存管理 slub算法 (一) 原理

一切的一切源於kmalloc_caches[12]這個數組,該數組的定義如下:

struct kmem_cache kmalloc_caches[PAGE_SHIFT] __cacheline_aligned;


每個數組元素對應一種大小的內存,可以把一個kmem_cache結構體看做是一個特定大小內存的零售商,整個slub系統中共有12個這樣的零售商,每個“零售商”只“零售”特定大小的內存,例如:有的“零售商”只"零售"8Byte大小的內存,有的只”零售“16Byte大小的內存。

每個零售商(kmem_cache)有兩個“部門”,一個是“倉庫”:kmem_cache_node,一個“營業廳”:kmem_cache_cpu。“營業廳”裡只保留一個slab,只有在營業廳(kmem_cache_cpu)中沒有空閒內存的情況下才會從倉庫中換出其他的slab。

所謂slab就是零售商(kmem_cache)批發的連續的整頁內存,零售商把這些整頁的內存分成許多小內存,然後分別“零售”出去,一個slab可能包含多個連續的內存頁。slab的大小和零售商有關。

相關數據結構:

物理頁按照對象(object)大小組織成單向鏈表,對象大小時候objsize指定的。例如16字節的對象大小,每個object就是16字節,每個object包含指向下一個object的指針,該指針的位置是每個object的起始地址+offset。每個object示意圖如下:

linux 內核 內存管理 slub算法 (一) 原理

void*指向的是下一個空閒的object的首地址,這樣object就連成了一個單鏈表。


向slub系統申請內存塊(object)時:slub系統把內存塊當成object看待
1、slub系統剛剛創建出來,這是第一次申請。
此時slub系統剛建立起來,營業廳(kmem_cache_cpu)和倉庫(kmem_cache_node)中沒有任何可用的slab可以使用,如下圖中1所示:

linux 內核 內存管理 slub算法 (一) 原理

因此只能向夥伴系統申請空閒的內存頁,並把這些頁面分成很多個object,取出其中的一個object標誌為已被佔用,並返回給用戶,其餘的object標誌為空閒並放在kmem_cache_cpu中保存。kmem_cache_cpu的freelist變量中保存著下一個空閒object的地址。上圖2表示申請一個新的slab,並把第一個空閒的object返回給用戶,freelist指向下一個空閒的object。

slub的kmem_cache_cpu中保存的slab上有空閒的object可以使用。
這種情況是最簡單的一種,直接把kmem_cache_cpu中保存的一個空閒object返回給用戶,並把freelist指向下一個空閒的object。

linux 內核 內存管理 slub算法 (一) 原理

slub已經連續申請了很多頁,現在kmem_cache_cpu中已經沒有空閒的object了,但kmem_cache_node的partial中有空閒的object 。所以從kmem_cache_node的partial變量中獲取有空閒object的slab,並把一個空閒的object返回給用戶。

linux 內核 內存管理 slub算法 (一) 原理

linux 內核 內存管理 slub算法 (一) 原理

上圖中,kmem_cache_cpu中已經都被佔用的slab放到倉庫中,kmem_cache_node中有兩個雙鏈表,partial和full,分別盛放不滿的slab(slab中有空閒的object)和全滿的slab(slab中沒有空閒的object)。然後從partial中挑出一個不滿的slab放到kmem_cache_cpu中。

linux 內核 內存管理 slub算法 (一) 原理

上圖中,kmem_cache_cpu中中找出空閒的object返回給用戶。
4、slub已經連續申請了很多頁,現在kmem_cache_cpu中保存的物理頁上已經沒有空閒的object可以使用了,而此時kmem_cache_node中沒有空閒的頁面了,只能向內存管理器(夥伴算法)申請slab。並把該slab初始化,返回第一個空閒的object。

linux 內核 內存管理 slub算法 (一) 原理

linux 內核 內存管理 slub算法 (一) 原理

上圖表示,kmem_cache_node中沒有空閒的object可以使用,所以只能重新申請一個slab。

linux 內核 內存管理 slub算法 (一) 原理

  • 把新申請的slab中的一個空閒object返回給用戶使用,freelist指向下一個空閒object。

  • 向slub系統釋放內存塊(object)時,如果kmem_cache_cpu中緩存的slab就是該object所在的slab,則把該object放在空閒鏈表中即可,如果kmem_cache_cpu中緩存的slab不是該object所在的slab,然後把該object釋放到該object所在的slab中。在釋放object的時候可以分為一下三種情況:

    object在釋放之前slab是full狀態的時候(slab中的object都是被佔用的),釋放該object後,這是該slab就是半滿(partail)的狀態了,這時需要把該slab添加到kmem_cache_node中的partial鏈表中。

    linux 內核 內存管理 slub算法 (一) 原理

    linux 內核 內存管理 slub算法 (一) 原理

    slab是partial狀態時(slab中既有object被佔用,又有空閒的),直接把該object加入到該slab的空閒隊列中即可。

    linux 內核 內存管理 slub算法 (一) 原理

    linux 內核 內存管理 slub算法 (一) 原理

    該object在釋放後,slab中的object全部是空閒的,還需要把該slab釋放掉。
    這一步產生一個完全空閒的slab,需要把這個slab釋放掉。

    linux 內核 內存管理 slub算法 (一) 原理

    linux 內核 內存管理 slub算法 (一) 原理

    這一步產生一個完全空閒的slab,需要把這個slab釋放掉。

    linux 內核 內存管理 slub算法 (一) 原理


    分享到:


    相關文章: