女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

基于Linux解決SLAB不足的SLUB分配器解決方案

454398 ? 來源:蝸窩科技 ? 作者:itrocker ? 2020-09-30 15:09 ? 次閱讀

Linux的物理內存管理采用了以頁為單位的buddy system(伙伴系統),但是很多情況下,內核僅僅需要一個較小的對象空間,而且這些小塊的空間對于不同對象又是變化的、不可預測的,所以需要一種類似用戶空間堆內存的管理機制(malloc/free)。然而內核對對象的管理又有一定的特殊性,有些對象的訪問非常頻繁,需要采用緩沖機制;對象的組織需要考慮硬件cache的影響;需要考慮多處理器以及NUMA架構的影響。90年代初期,在Solaris 2.4操作系統中,采用了一種稱為“slab”(原意是大塊的混凝土)的緩沖區分配和管理方法,在相當程度上滿足了內核的特殊需求。

多年以來,SLAB成為linux kernel對象緩沖區管理的主流算法,甚至長時間沒有人愿意去修改,因為它實在是非常復雜,而且在大多數情況下,它的工作完成的相當不錯。但是,隨著大規模多處理器系統和 NUMA系統的廣泛應用,SLAB 分配器逐漸暴露出自身的嚴重不足:

1)。 緩存隊列管理復雜;

2)。 管理數據存儲開銷大;

3)。 對NUMA支持復雜;

4)。 調試調優困難;

5)。 摒棄了效果不太明顯的slab著色機制;

針對這些SLAB不足,內核開發人員Christoph Lameter在Linux內核2.6.22版本中引入一種新的解決方案:SLUB分配器。SLUB分配器特點是簡化設計理念,同時保留SLAB分配器的基本思想:每個緩沖區由多個小的slab 組成,每個 slab 包含固定數目的對象。SLUB分配器簡化kmem_cache,slab等相關的管理數據結構,摒棄了SLAB 分配器中眾多的隊列概念,并針對多處理器、NUMA系統進行優化,從而提高了性能和可擴展性并降低了內存的浪費。為了保證內核其它模塊能夠無縫遷移到SLUB分配器,SLUB還保留了原有SLAB分配器所有的接口API函數。

(注:本文源碼分析基于linux-4.1.x)

整體數據結構關系如下圖所示:

1 SLUB分配器的初始化

SLUB初始化有兩個重要的工作:第一,創建用于申請struct kmem_cache和struct kmem_cache_node的kmem_cache;第二,創建用于常規kmalloc的kmem_cache。

1.1 申請kmem_cache的kmem_cache

第一個工作涉及到一個“先有雞還是先有蛋”的問題,因為創建kmem_cache需要從kmem_cache的緩沖區申請,而這時候還沒有創建kmem_cache的緩沖區。kernel的解決辦法是先用兩個靜態變量boot_kmem_cache和boot_kmem_cache_node來保存struct kmem_cach和struct kmem_cache_node緩沖區管理數據,以兩個靜態變量為基礎申請大小為struct kmem_cache和struct kmem_cache_node對象大小的slub緩沖區,隨后再從這些緩沖區中分別申請兩個kmem_cache,然后把boot_kmem_cache和boot_kmem_cache_node中的內容拷貝到新申請的對象中,從而完成了struct kmem_cache和struct kmem_cache_node管理結構的bootstrap(自引導)。

void __init kmem_cache_init(void)

{

//聲明靜態變量,存儲臨時kmem_cache管理結構

static __initdata struct kmem_cache boot_kmem_cache,

boot_kmem_cache_node;

???

kmem_cache_node = &boot_kmem_cache_node;

kmem_cache = &boot_kmem_cache;

//申請slub緩沖區,管理數據放在臨時結構中

create_boot_cache(kmem_cache_node, “kmem_cache_node”,

sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN);

create_boot_cache(kmem_cache, “kmem_cache”,

offsetof(struct kmem_cache, node) +

nr_node_ids * sizeof(struct kmem_cache_node *),

SLAB_HWCACHE_ALIGN);

//從剛才掛在臨時結構的緩沖區中申請kmem_cache的kmem_cache,并將管理數據拷貝到新申請的內存中

kmem_cache = bootstrap(&boot_kmem_cache);

//從剛才掛在臨時結構的緩沖區中申請kmem_cache_node的kmem_cache,并將管理數據拷貝到新申請的內存中

kmem_cache_node = bootstrap(&boot_kmem_cache_node);

???

}

1.2 創建kmalloc常規緩存

原則上系統會為每個2次冪大小的內存塊申請一個緩存,但是內存塊過小時,會產生很多碎片浪費,所以系統為96B和192B也各自創建了一個緩存。于是利用了一個size_index數組來幫助確定小于192B的內存塊使用哪個緩存

void __init create_kmalloc_caches(unsigned long flags)

{

???

/*使用SLUB時KMALLOC_SHIFT_LOW=3,KMALLOC_SHIFT_HIGH=13

也就是說使用kmalloc能夠申請的最小內存是8B,最大內存是8KB

申請內存是向上對其2的n次冪,創建對應大小緩存保存在kmalloc_caches [n]*/

for (i = KMALLOC_SHIFT_LOW; i 《= KMALLOC_SHIFT_HIGH; i++) {

if (!kmalloc_caches[i]) {

kmalloc_caches[i] = create_kmalloc_cache(NULL,

1 《《 i, flags);

}

/*

* Caches that are not of the two-to-the-power-of size.

* These have to be created immediately after the

* earlier power of two caches

*/

/*有兩個例外,大小為64~96B和128B~192B,單獨創建了兩個緩存

保存在kmalloc_caches [1]和kmalloc_caches [2]*/

if (KMALLOC_MIN_SIZE 《= 32 && !kmalloc_caches[1] && i == 6)

kmalloc_caches[1] = create_kmalloc_cache(NULL, 96, flags);

if (KMALLOC_MIN_SIZE 《= 64 && !kmalloc_caches[2] && i == 7)

kmalloc_caches[2] = create_kmalloc_cache(NULL, 192, flags);

}

???

}

2 緩存的創建與銷毀

2.1 緩存的創建

創建緩存通過接口kmem_cache_create進行,在創建新的緩存以前,嘗試找到可以合并的緩存,合并條件包括對對象大小以及緩存屬性的判斷,如果可以合并則直接返回已存在的kmem_cache,并創建一個kobj鏈接指向同一個節點。

創建新的緩存主要是申請管理結構暫用的空間,并初始化,這些管理結構包括kmem_cache、kmem_cache_nodes、kmem_cache_cpu。同時在sysfs創建kobject節點。最后把kmem_cache加入到全局cahce鏈表slab_caches中。

2.2 緩存的銷毀

銷毀過程比創建過程簡單的多,主要工作是釋放partial隊列所有page,釋放kmem_cache_cpu,釋放每個node的kmem_cache_node,最后釋放kmem_cache本身。

3 申請對象

對象是SLUB分配器中可分配的內存單元,與SLAB相比,SLUB對象的組織非常簡潔,申請過程更加高效。SLUB沒有任何管理區結構來管理對象,而是將對象之間的關聯嵌入在對象本身的內存中,因為申請者并不關心對象在分配之前內存的內容是什么。而且各個SLUB之間的關聯,也利用page自身結構進行處理。

每個CPU都有一個slab作為本地高速緩存,只要slab所在的node與申請者要求的node匹配,同時該slab還有空閑對象,則直接在cpu_slab中取出空閑對象,否則就進入慢速路徑。

每個對象內存的offset偏移位置都存放著下一個空閑對象,offset通常為0,也就是復用對象內存的第一個字來保存下一個空閑對象的指針,當滿足條件(flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) 或者有對象構造函數時,offset不為0,每個對象的結構如下圖。

cpu_slab的freelist則保存著當前第一個空閑對象的地址。

如果本地CPU緩存沒有空閑對象,則申請新的slab;如果有空閑對象,但是內存node不相符,則deactive當前cpu_slab,再申請新的slab。

deactivate_slab主要進行兩步工作:

第一步,將cpu_slab的freelist全部釋放回page-》freelist;

第二部,根據page(slab)的狀態進行不同操作,如果該slab有部分空閑對象,則將page移到kmem_cache_node的partial隊列;如果該slab全部空閑,則直接釋放該slab;如果該slab全部占用,而且開啟了CONFIG_SLUB_DEBUG編譯選項,則將page移到full隊列。

page的狀態也從frozen改變為unfrozen。(frozen代表slab在cpu_slub,unfroze代表在partial隊列或者full隊列)。

申請新的slab有兩種情況,如果cpu_slab的partial隊列不為空,則取出隊列中下一個page作為新的cpu_slab,同時再次檢測內存node是否相符,還不相符則循環處理。

如果cpu_slab的partial隊列為空,則查看本node的partial隊列是否為空,如果不空,則取出page;如果為空,則看一定距離范圍內其它node的partial隊列,如果還為空,則需要創建新slab。

創建新slab其實就是申請對應order的內存頁,用來放足夠數量的對象。值得注意的是其中order以及對象數量的確定,這兩者又是相互影響的。order和object數量同時存放在kmem_cache成員kmem_cache_order_objects中,低16位用于存放object數量,高位存放order。order與object數量的關系非常簡單:((PAGE_SIZE 《《 order) - reserved) / size。

下面重點看calculate_order這個函數

static inline int calculate_order(int size, int reserved)

{

???

//嘗試找到order與object數量的最佳配合方案

//期望的效果就是剩余的碎片最小

min_objects = slub_min_objects;

if (!min_objects)

min_objects = 4 * (fls(nr_cpu_ids) + 1);

max_objects = order_objects(slub_max_order, size, reserved);

min_objects = min(min_objects, max_objects);

//fraction是碎片因子,需要滿足的條件是碎片部分乘以fraction小于slab大小

// (slab_size - reserved) % size 《= slab_size / fraction

while (min_objects 》 1) {

fraction = 16;

while (fraction 》= 4) {

order = slab_order(size, min_objects,

slub_max_order, fraction, reserved);

if (order 《= slub_max_order)

return order;

//放寬條件,容忍的碎片大小增倍

fraction /= 2;

}

min_objects--;

}

//嘗試一個slab只包含一個對象

order = slab_order(size, 1, slub_max_order, 1, reserved);

if (order 《= slub_max_order)

return order;

//使用MAX_ORDER且一個slab只含一個對象

order = slab_order(size, 1, MAX_ORDER, 1, reserved);

if (order 《 MAX_ORDER)

return order;

return -ENOSYS;

}

4 釋放對象

從上面申請對象的流程也可以看出,釋放的object有幾個去處:

1)cpu本地緩存slab,也就是cpu_slab;

2)放回object所在的page(也就是slab)中;另外要處理所在的slab:

2.1)如果放回之后,slab完全為空,則直接銷毀該slab;

2.2)如果放回之前,slab為滿,則判斷slab是否已被凍結;如果已凍結,則不需要做其他事;如果未凍結,則將其凍結,放入cpu_slab的partial隊列;如果cpu_slab partial隊列過多,則將隊列中所有slab一次性解凍到各自node的partial隊列中。

值得注意的是cpu partial隊列的功能是個可選項,依賴于內核選項CONFIG_SLUB_CPU_PARTIAL,如果沒有開啟,則不使用cpu partial隊列,直接使用各個node的partial隊列。
編輯:hfy

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 處理器
    +關注

    關注

    68

    文章

    19793

    瀏覽量

    233405
  • cpu
    cpu
    +關注

    關注

    68

    文章

    11029

    瀏覽量

    215860
  • Linux
    +關注

    關注

    87

    文章

    11449

    瀏覽量

    212702
  • 內存管理
    +關注

    關注

    0

    文章

    168

    瀏覽量

    14464
收藏 人收藏

    評論

    相關推薦
    熱點推薦

    PS2-88,PS2-88/NF功率分配器MCLI

    PS2-88,PS2-88/NF功率分配器MCLIPS2-88功率分配器是MCLI品牌推出的一款高性能射頻微波器件,屬于PS2系列2路功率分配器。PS2-88功率分配器是一款高性能的射
    發表于 03-20 09:31

    PS2-185/NF帶狀線2路電源分配器

    PS2-185/NF帶狀線2路電源分配器PS2-185/NF帶狀線2路電源分配器具備高可靠性,通過不同種類的結構(如帶狀線、微帶和集總器件方式)來適合各種需求和應用。主要特性電氣性能頻率范圍
    發表于 01-08 09:23

    CDCL1810A 1.8V、10 輸出高性能時鐘分配器數據表

    電子發燒友網站提供《CDCL1810A 1.8V、10 輸出高性能時鐘分配器數據表.pdf》資料免費下載
    發表于 08-23 10:08 ?0次下載
    CDCL1810A 1.8V、10 輸出高性能時鐘<b class='flag-5'>分配器</b>數據表

    CDCL1810 1.8V 10路輸出高性能時鐘分配器數據表

    電子發燒友網站提供《CDCL1810 1.8V 10路輸出高性能時鐘分配器數據表.pdf》資料免費下載
    發表于 08-22 11:14 ?0次下載
    CDCL1810 1.8V 10路輸出高性能時鐘<b class='flag-5'>分配器</b>數據表

    CDCE18005高性能時鐘分配器數據表

    電子發燒友網站提供《CDCE18005高性能時鐘分配器數據表.pdf》資料免費下載
    發表于 08-21 11:12 ?0次下載
    CDCE18005高性能時鐘<b class='flag-5'>分配器</b>數據表

    CDCE62005高性能時鐘發生器和分配器數據表

    電子發燒友網站提供《CDCE62005高性能時鐘發生器和分配器數據表.pdf》資料免費下載
    發表于 08-21 11:12 ?0次下載
    CDCE62005高性能時鐘發生器和<b class='flag-5'>分配器</b>數據表

    LMK01000高性能時鐘緩沖器、分頻器和分配器數據表

    電子發燒友網站提供《LMK01000高性能時鐘緩沖器、分頻器和分配器數據表.pdf》資料免費下載
    發表于 08-21 09:53 ?0次下載
    LMK01000高性能時鐘緩沖器、分頻器和<b class='flag-5'>分配器</b>數據表

    液壓分配器起什么作用的

    液壓分配器是一種用于控制液壓系統中液體流量和壓力的設備。它在許多工業和工程應用中發揮著重要作用,例如在液壓升降機、液壓挖掘機、液壓起重機等設備中。以下是液壓分配器的主要功能和原理: 流量控制 :液壓分配器
    的頭像 發表于 07-10 10:56 ?1837次閱讀

    液壓分配器工作原理是什么

    液壓分配器,又稱液壓多路閥,是液壓系統中的關鍵部件之一。它的作用是將液壓泵輸出的油液分配到各個執行機構,實現液壓系統的控制和調節。 一、液壓分配器的工作原理 液壓分配器的基本組成 液壓
    的頭像 發表于 07-10 10:55 ?3769次閱讀

    液壓分配器壓力調整方法有哪些

    液壓分配器,又稱液壓分配器或液壓分流器,是一種用于液壓系統中的設備,主要用于將液壓系統中的壓力油分配到各個執行元件,以實現對液壓系統的控制和調節。 一、液壓分配器壓力調整的重要性 液壓
    的頭像 發表于 07-10 10:53 ?3379次閱讀

    單線分配器與雙線分配器的區別是什么

    單線分配器與雙線分配器是兩種不同類型的電子設備,它們在通信、廣播、電視等領域中有著廣泛的應用。本文將介紹單線分配器與雙線分配器的區別。 一、定義 單線
    的頭像 發表于 07-10 10:44 ?1647次閱讀

    四路數據分配器的基本概念、工作原理、應用場景及設計方法

    四路數據分配器是一種數字電路元件,它的作用是將一個數據輸入信號分配成多個數據輸出信號。 1. 四路數據分配器的基本概念 四路數據分配器是一種多路復用器(Multiplexer),它將一
    的頭像 發表于 07-10 10:42 ?2800次閱讀

    八路數據分配器的基本概念及工作原理

    八路數據分配器是一種常見的電子設備,用于將一個輸入信號分配到多個輸出端。在本文中,我們將詳細介紹八路數據分配器的基本概念、工作原理、應用場景以及設計方法。 一、八路數據分配器的基本概念
    的頭像 發表于 07-10 10:40 ?3420次閱讀

    DS90LV110T 1至10 LVDS數據/時鐘分配器數據表

    電子發燒友網站提供《DS90LV110T 1至10 LVDS數據/時鐘分配器數據表.pdf》資料免費下載
    發表于 07-05 11:37 ?0次下載
    DS90LV110T 1至10 LVDS數據/時鐘<b class='flag-5'>分配器</b>數據表

    DS90LV110AT 1至10 LVDS數據/時鐘分配器數據表

    電子發燒友網站提供《DS90LV110AT 1至10 LVDS數據/時鐘分配器數據表.pdf》資料免費下載
    發表于 07-05 11:34 ?0次下載
    DS90LV110AT 1至10 LVDS數據/時鐘<b class='flag-5'>分配器</b>數據表