歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux內存分配slub的幾個疑問

Linux內存分配slub的幾個疑問

日期:2017/2/28 16:24:40   编辑:Linux教程

對於SLUB不熟的同學可以先跳過了,涉及的東西比較細致。

簡單來說SLUB的結構是N(CPU數)個kmem_cache_cpu,和一個kmem_cache_node組成。其中kmem_cache_cpu的目的是為了從技術層面上提高CPU命中緩存,以及在同一個頁面上不出現一個髒的內存(即不同時被多個CPU持有)。我把這個實現機制手工在WINDOWS下實現了一套,在開啟多個kmem_cache_cpu的時候出現了個問題:

1.在釋放對象的時候,判斷是否是當前kmem_cache_cpu頁面所在

2.如果是,則直接插入

3.如果不是,釋放到鄰居節點

如果是單個kmem_cache_cpu肯定沒問題,但是在多個kmem_cache_cpu下,很可能會把其中一個kmem_cache_cpu已經持有的頁面釋放到鄰居節點。舉個例子:

假設一個頁面地址是0-9,

kmem_cache_cpu1,持有A頁面,空閒的情況為A0-A5

kmem_cache_cpu2,持有B頁面,

當輪到kmem_cache_cpu2執行的時候,一個A頁面的地址A6釋放,程序檢測到非B頁面,則直接釋放到鄰居節點。那麼這個時候A頁面已經被切割成兩段,並且在公共的鄰居節點中。這個時候反而是增加了內存的髒度。後仔細看代碼發現,源碼中有這段:

<SPAN ><SPAN >struct kmem_cache_cpu {
void **freelist; /* Pointer to first free per cpu object */
struct page *page; /* The slab from which we are allocating */
int node; /* The node of the page (or -1 for debug) */
unsigned int offset; /* Freepointer offset (in word units) */
unsigned int objsize; /* Size of an object (from kmem_cache) */
#ifdef CONFIG_SLUB_STATS
unsigned stat[NR_SLUB_STAT_ITEMS];
#endif
};</SPAN></SPAN>

注意到struct page *page;了嗎?之前一直忽略它。並且真相在分配的函數裡面,

如果freelist無效的話,會多查詢一次page頁的地址。

2011年1月15日增

細致看了下,覺得這個地方還是有BUG。

釋放上就兩個步驟

1)走本地PAGE

2)NODE節點

申請上比較復雜

1)走本地freelist

2)走本頁page

3)走鄰居節點

4)走系統

並且做了一些看似應該釋放做的事:

1)如果page和freelist都為空,則走deactivate_slab();

deactivate_slab中有很多兼容的判斷,要一一捨棄。閱讀源碼最痛苦的就是這點。

其中用到了個值page->inuse。這個值很奇怪,它指的是在kmem_cache_cpu當前+使用中的對象,如果釋放了則

進行減一,所以你看不到他的++。

1)如果page->inuse大於0,並且freelist還有值,加入鄰居。這個估計是兼容的代碼,之前的判斷freelist不為空

2)反之,加到鄰居鏈表。

3)如果當前鄰居鏈表滿,則釋放掉

2)如果freelist為空,page不為空,很可能其他的kmem_cache_cpu釋放了對象,則走load_freelist:

疑問一:就是加入鄰居鏈表和釋放加入鄰居鏈表的沖突。從條件上看,其實兩個都是依賴page->freelist是否為空加入,但是在deactivate_slab加入鄰居節點後,並沒有對page->freelist進行處理,如果這時候有對象釋放,是否會造成重復加入?

這個疑問是我弄錯了,如果page->inuse==0,表示對象都已經釋放,不會觸發再次釋放

疑問二:在多個kmem_cache_cpu情況下,釋放的元素都是放到共同的鄰居頁面,很有可能被其他的kmem_cache_cpu直接取到,這樣就造成2個不同的kmem_cache_cpu共享同個頁面,這就違背了裡面緩存命中的功能。

Copyright © Linux教程網 All Rights Reserved