內存管理(21)釋放slab對象

先說總結:

1.slab對象先會歸還給共享緩存池,其次歸還給(完全或部分)空閒對象slab鏈表,最後前面的都滿了放不下了才會被真正釋放歸還給系統

2.空閒對象是以slab為粒度進行歸還的,只有slab下的對象全部空閒才會開始進行slab歸還或者slab釋放

3.最終如果需要釋放給系統,按照一個slab所佔用的物理頁進行釋放。1個slab所需物理頁面的數量由gfporder決定。

下面是代碼細節:

slab對象的釋放的核心函數kmem_cache_free,該函數最終會調用__cache_free函數來完成這個行為。下面看它的實現細節:

__cache_free函數

內存管理(21)釋放slab對象

__cache_free實現

  • 第9行:獲取到slab描述符所指向的當前CPU的per-cpu變量ac
  • 第12~13行:是NUMA系統的處理情況,後面是非NUMA系統的情況,此處以非NUMA系統來說明。NUMA系統的slab釋放本質與非NUMA系統是一樣的。
  • 第15~17行:如果本地緩衝池的可用的對象數量低於對象數量的閾值,那就通過ac_put_obj把對象加入本地緩衝池
  • 第19行:如果本地緩衝池可用對象已滿,就調用cache_flusharray釋放緩衝池

cache_flusharray函數

內存管理(21)釋放slab對象

cache_flusharray實現1

  • 如果存在共享緩存池,檢測是否有向共享緩衝池借用對象空間,如果有則退還給共享緩存池。退還的對象數量就是共享緩存池缺少的對象數量。
  • 之後就跳轉帶free_done位置
  • 如果不存在共享緩存池則在free_block將活躍的對象置為空閒對象並加入到指定的空閒對象鏈表,如果鏈表放不下的就釋放其內存空間歸還給系統。其實現細節如下↓
內存管理(21)釋放slab對象

cache_flusharray實現2

  • 前面free_block的時候提到list中存放的就是需要歸還系統的內存頁,而slabs_destroy做的工作就是釋放這些內存頁。其實現細節如下↓
  • 將batchcount之後的空間前移到對象實體首地址,方便對象的清理工作。

free_block函數

內存管理(21)釋放slab對象

free_block實現1

  • 依次遍歷所有對象
  • virt_to_head_page通過對象地址找到其對應的內存頁首地址
  • 將該對象的內存頁LRU節點從LRU鏈表移除
  • slab_put_object將對象從活躍置為空閒
  • slab中的空閒對象數目自加1
內存管理(21)釋放slab對象

free_block實現2

  • 如果active等於0,內存頁下對應slab的活躍對象已全部清0轉為空閒。在此條件下,如果slab節點中空閒對象的總數已超出其閾值,則從free_object總數中收縮一個slab的對象數的同時將其加入到list,以便後面釋放內存歸還給系統;如果沒有超出閾值,則將該page加入到對象完全空閒鏈表
  • 如果active不等於0,表示對應內存頁的slab對象還沒有完全空閒,有部分是非空閒的。所以將其加入到對象不完全空閒鏈表

slabs_destroy函數

內存管理(21)釋放slab對象

slabs_destroy實現

  • 顯而易見依次從list中去一個一個的摘下來在slab_destroy中去釋放內存空間,所以內存的釋放在slab_destroy中處理,其實現如下↓

slab_destroy函數

內存管理(21)釋放slab對象

slab_destroy實現

  • 兩種情況最終都會通過kmem_freepages來釋放內存頁,其實現如下↓
  • 如果freelist不包含在slab裡面,還要單獨對freelist所佔用的內存空間進行釋放。最終同樣會以對象的形式進行釋放。

kmem_freepages函數

內存管理(21)釋放slab對象

kmem_freepages實現

  • 在kmem_freepages函數在做了一些釋放前的準備工作後最終會調用__free_pages將內存頁一頁一頁的釋放歸還給系統,__free_pages這個函數前面講過就不再贅述。


分享到:


相關文章: