slub機制徹底圖解分析
核心管理頁面使用了2個演算法:夥伴演算法和slub演算法,夥伴演算法以頁為單位管理記憶體,但在大多數情況下,程式需要的並不是一整頁,而是幾個、幾十個位元組的小記憶體。於是需要另外一套系統來完成對小記憶體的管理,這就是slub系統。slub系統執行在夥伴系統之上,為核心提供小記憶體管理的功能。
slub把記憶體分組管理,每個組分別包含2^3、2^4、...2^11個位元組,在4K頁大小的預設情況下,另外還有兩個特殊的組,分別是96B和192B,共11組。之所以這樣分配是因為如果申請2^12B大小的記憶體,就可以使用夥伴系統提供的介面直接申請一個完整的頁面即可。
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看待
- 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。 - slub的kmem_cache_cpu中儲存的slab上有空閒的object可以使用。
這種情況是最簡單的一種,直接把kmem_cache_cpu中儲存的一個空閒object返回給使用者,並把freelist指向下一個空閒的object。 - slub已經連續申請了很多頁,現在kmem_cache_cpu中已經沒有空閒的object了,但kmem_cache_node的partial中有空閒的object 。所以從kmem_cache_node的partial變數中獲取有空閒object的slab,並把一個空閒的object返回給使用者。
上圖中,kmem_cache_cpu中已經都被佔用的slab放到倉庫中,kmem_cache_node中有兩個雙連結串列,partial和full,分別盛放不滿的slab(slab中有空閒的object)和全滿的slab(slab中沒有空閒的object)。然後從partial中挑出一個不滿的slab放到kmem_cache_cpu中。
上圖中,kmem_cache_cpu中中找出空閒的object返回給使用者。 - 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的時候可以分為一下三種情況:
- object在釋放之前slab是full狀態的時候(slab中的object都是被佔用的),釋放該object後,這是該slab就是半滿(partail)的狀態了,這時需要把該slab新增到kmem_cache_node中的partial連結串列中。
- slab是partial狀態時(slab中既有object被佔用,又有空閒的),直接把該object加入到該slab的空閒佇列中即可。
- 該object在釋放後,slab中的object全部是空閒的,還需要把該slab釋放掉。
這一步產生一個完全空閒的slab,需要把這個slab釋放掉。
以上是slub演算法的主要原理。
相關文章
- slub機制偽總結
- 徹底理解 Dart mixin 機制Dart
- 徹底剖析JVM類載入機制JVM
- 徹底搞懂HTTPS的加密機制HTTP加密
- 徹底理解安卓應用無響應機制安卓
- 轉:徹底弄懂HTTP快取機制及原理HTTP快取
- 這一次,徹底弄懂 JavaScript 執行機制JavaScript
- 圖解|這次,徹底理解MySQL的索引圖解MySql索引
- http系列--徹底理解瀏覽器的快取機制(http快取機制)HTTP瀏覽器快取
- HashMap原始碼分析(二):看完徹底瞭解HashMapHashMap原始碼
- 圖解|從根上徹底理解MySQL的索引圖解MySql索引
- 從CPU Cache出發徹底弄懂volatile/synchronized/cas機制synchronized
- Spirit帶你徹底瞭解事件捕獲和冒泡機制事件
- 深入理解JavaScript之徹底弄懂JsEventLoop執行機制JavaScriptJSOOP
- 這一次,徹底弄懂JS執行機制(Event Loop)JSOOP
- 圖解Android事件分發機制(深入底層原始碼)圖解Android事件原始碼
- 徹底搞懂Redis持久化機制,輕鬆應對工作面試Redis持久化面試
- drbd腦裂徹底解決
- 實踐這一次,徹底搞懂瀏覽器快取機制瀏覽器快取
- Java 底層機制Java
- 【轉】JAVA IO 設計模式徹底分析Java設計模式
- Java 徹底搞清楚進位制轉換Java
- 看完了程式同步與互斥機制,我終於徹底理解了 PV 操作
- 徹底解決Oracle中文亂碼Oracle
- 圖解JS執行機制圖解JS
- 圖解Golang垃圾回收機制!圖解Golang
- NEO共識機制圖解圖解
- 徹底瞭解阿里在中國最大的電商對手京東–資訊圖阿里
- win10怎樣徹底刪除印表機 win10如何徹底刪除印表機驅動Win10
- 徹底解決程式亂碼問題
- 徹底搞懂徹底搞懂事件驅動模型 - Reactor事件模型React
- 幫你徹底搞懂JS中的prototype、__proto__與constructor(圖解)JSStruct圖解
- 徹底理解synchronizedsynchronized
- 徹底搞懂 RxJavaRxJava
- Java SPI機制總結系列之萬字最詳細圖解Java SPI機制原始碼分析Java圖解原始碼
- 分頁機制圖文詳解
- win10無法徹底關機如何解決_win10無法徹底關機怎麼修復Win10
- 徹底解決Python編碼問題Python