歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

內存管理四之工作原理

在函數實現中,如果申請的內存空間較大的話,會從buddy系統申請若干內存頁面,如果申請的內存空間大小較小的話,會從slab系統中申請內存空間。
1、Zone
Linux中Node、Zone和頁的關系
每個結點的內存被分為多個塊,稱為zones,它表示內存中一段區域。一個zone用struct zone結構描述,zone的類型主要有ZONE_DMA、ZONE_NORMAL和ZONE_HIGHMEM。ZONE_DMA位於低端的內存空間,用於某些舊的ISA設備。ZONE_NORMAL的內存直接映射到Linux內核線性地址空間的高端部分,ZONE_HIGHMEM位於物理地址高於896MB的區域。例如,在X86中,zone的物理地址如下:
內核空間只有1GB線性地址,如果使用大於1GB的物理內存就沒法直接映射到內核線性空間了。當系統中的內存大於896MB時,把內核線性空間分為兩部分,內核中低於896MB線性地址空間直接映射到低896MB的物理地址空間;高於896MB的128MB內核線性空間用於動態映射ZONE_HIGHMEM內存區域(即物理地址高於896MB的物理空間)。
3、Buddy
如上圖所示,每個zone區域都采用伙伴系統(buddy system)來管理空閒內存頁面。把所有的空閒頁框分組為11個塊鏈表,每個塊鏈表分別包含大小為1,2,4,8,16,32,64,128,256,512和1024個連續的頁框。鏈表編號分別為0,1,2,3,… k… 10。
從buddy system中申請頁面過程:
根據申請存儲區域大小查找對應的編號為K的塊鏈表。
如果編號K的鏈表為空,則向編號為k+1的鏈表申請一個存儲區域。如果編號為k+1鏈表不為空,系統從編號為k+1的鏈表上拆下一個區域,並將拆下的區域分為兩個2^k的區域,一個返還給申請者,另一個則掛到編號為k的鏈表。
如果編號為k+1的鏈表也為空,編號為k+2的鏈表不為空。則從k+2的鏈表中拆下一個區域變為兩個2^(k+1)區域,一個掛到編號為k+1的鏈表上,把另一個拆為兩個2^k的區域,一個返還給申請者,把另一個掛到編號為k的鏈表上。
如果k+2的鏈表也為空,則一直向上迭代,直到編號為10的鏈表為止,如果編號為10的鏈表還為空,則申請失敗。
向buddysystem中釋放頁面過程:
在向buddysystem 釋放頁面時,總會檢測釋放的頁面和鏈表中其他頁面是否可以組成一個更大一級的頁面,如果可以組成,則把這兩個區域組成一個並掛到更高一級的鏈表中。這個過程是迭代的,釋放過程會一層層向上找伙伴,然後合並成更大的,再向上找伙伴,實在找不到了就停止了!
疑問:按照上面的說法,是否會出現這種情況,在釋放某個頁面導致所有頁面都組成了標號為10的連續頁面了。等到再需要分配1個頁面時,又要一級一級地拆分。這樣的話效率是否很低??
是否在buddysystem 每個鏈表結構中設一個門限值會更好?釋放時標記一下可以組成buddy的兩個連續區域,只有該級空閒的區域個數超過門限後才組成buddy並掛到上一級鏈表上。當然,這個門限值可以由內核根據目前總的空閒頁面數量進行動態調整。
4、Slab
下圖中給出了 slab 結構的高層組織結構。在最高層是 cache_chain,這是一個 slab 緩存的鏈接列表。可以用來查找最適合所需要的分配大小的緩存。cache_chain 的每個元素都是一個 kmem_cache 結構的引用。一個kmem_cache中的所有object大小都相同。
slab 分配器的主要結構
slab是基於buddysystem的, 每個slab占用一個或多個連續頁,即一個buddy鏈中的1個或多個頁面。
每個緩存都包含了一個 slabs 列表,這是一段連續的內存塊(通常都是頁面)。存在 3 種 slab:
slabs_full
完全分配的 slab ,即其維護的空閒object鏈表為空
slabs_partial
部分分配的 slab
slabs_empty
空 slab,或者沒有對象被分配,即其inuse標志位0.
注意 slabs_empty 列表中的 slab 是進行回收的主要備選對象。正是通過此過程,slab 所使用的內存被返回給操作系統供其他用戶使用。
slab 列表中的每個 slab 都是一個連續的內存塊(從buddy申請的一個或多個連續頁),它們被劃分成一個個對象,這些對象是分配和釋放的基本元素。在slab擴展時或把slab占用的內存塊釋放到buddy系統時, slab是最小分配單位。通常來說,每個 slab被分配為多個對象。由於對象是從
slab 中進行分配和釋放的,因此單個 slab 可以在 slab 列表之間進行移動。例如,當一個 slab中的所有對象都被使用完時,就從slabs_partial列表中移動到slabs_full列表中。當一個
slab 完全被分配並且有對象被釋放後,就從slabs_full列表中移動到slabs_partial列表中。當所有對象都被釋放之後,就從slabs_partial列表移動到slabs_empty列表中。
slab 背後的動機與傳統的內存管理模式相比, slab
緩存分配器提供了很多優點。
首先,內核通常依賴於對小對象的分配,它們會在系統生命周期內進行無數次分配。slab 緩存分配器通過對類似大小的對象進行緩存而提供這種功能,從而避免了常見的碎片問題。
其次,slab 分配器還支持通用對象的初始化,從而避免了為同一目而對一個對象重復進行初始化。
最後,slab 分配器還可以支持硬件緩存對齊和著色,這允許不同緩存中的對象占用相同的緩存行,從而提高緩存的利用率並獲得更好的性能。
本文源自:http://blog.chinaunix.net/uid-27052262-id-3237894.html
參考:
源文檔 <http://blog.chinaunix.net/uid-27052262-id-3259902.html>
源文檔 </content/529556.html>
源文檔 </content/6627189.html>
源文檔 <http://totoxian.iteye.com/blog/1219991>
源文檔 </content/3973598.html>
源文檔 <http://www.eygle.com/digest/2012/05/linux_page_table.html>
Copyright © Linux教程網 All Rights Reserved