slub機制完全圖解分析

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

        slub把內存分組管理,每一個組分別包含2^三、2^四、...2^11個字節,在4K頁大小的默認狀況下,另外還有兩個特殊的組,分別是96B和192B,共11組。之因此這樣分配是由於若是申請2^12B(4KB)大小的內存,就可使用夥伴系統提供的接口直接申請一個完整的頁面便可。算法

        slub就至關於零售商,它向夥伴系統「批發」內存,而後在零售出去。一下是整個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示意圖以下:接口

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

        向slub系統申請內存塊(object)時:slub系統把內存塊當成object看待。內存

  1. slub系統剛剛建立出來,這是第一次申請。
    此時slub系統剛創建起來,營業廳(kmem_cache_cpu)和倉庫(kmem_cache_node)中沒有任何可用的slab,以下圖中1所示:
                  
    所以只能向夥伴系統申請空閒的內存頁,並把這些頁面分紅不少個object,取出其中的一個object標誌爲已被佔用,並返回給用戶,其他的object標誌爲空閒並放在kmem_cache_cpu中保存。kmem_cache_cpu的freelist變量中保存着下一個空閒object的地址。上圖2表示申請一個新的slab,並把第一個空閒的object返回給用戶,freelist指向下一個空閒的object。
     
  2. slub的kmem_cache_cpu中保存的slab上有空閒的object可使用。
    這種狀況是最簡單的一種,直接把kmem_cache_cpu中保存的一個空閒object返回給用戶,並把freelist指向下一個空閒的object。
                
     
  3. slub已經連續申請了不少頁,如今kmem_cache_cpu中已經沒有空閒的object了,但kmem_cache_node的partial中有空閒的object 。因此從kmem_cache_node的partial變量中獲取有空閒object的slab,並把一個空閒的object返回給用戶。
  4.          
              
    上圖中,kmem_cache_cpu中已經都被佔用的slab放到倉庫中,kmem_cache_node中有兩個雙鏈表,partial和full,分別盛放不滿的slab(slab中有空閒的object)和全滿的slab(slab中沒有空閒的object)。而後從partial中挑出一個不滿的slab放到kmem_cache_cpu中。
                 
    上圖中,kmem_cache_cpu中中找出空閒的object返回給用戶。

     
  5. slub已經連續申請了不少頁,如今kmem_cache_cpu中保存的物理頁上已經沒有空閒的object可使用了,而此時kmem_cache_node中沒有空閒的頁面了,只能向內存管理器(夥伴算法)申請slab。並把該slab初始化,返回第一個空閒的object。
                  
                 
    上圖表示,kmem_cache_node中沒有空閒的object可使用,因此只能從新申請一個slab。


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

      向slub系統釋放內存塊(object)時,若是kmem_cache_cpu中緩存的slab就是該object所在的slab,則把該object放在空閒鏈表中便可,若是kmem_cache_cpu中緩存的slab不是該object所在的slab,而後把該object釋放到該object所在的slab中。在釋放object的時候能夠分爲一下三種狀況:

 

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

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

                   
     
  3. 該object在釋放後,slab中的object所有是空閒的,還須要把該slab釋放掉。
                     

                    
    這一步產生一個徹底空閒的slab,須要把這個slab釋放掉。

                    
     

 

     以上是slub算法的主要原理。

相關文章
相關標籤/搜索