NGINX原理 之 SLAB分配机制(转)
1 引言
? 眾所周知,操作系統(tǒng)使用伙伴系統(tǒng)管理內(nèi)存,不僅會造成大量的內(nèi)存碎片,同時處理效率也較低下。SLAB是一種內(nèi)存管理機(jī)制,其擁有較高的處理效率,同時也有效的避免內(nèi)存碎片的產(chǎn)生,其核心思想是預(yù)分配。其按照SIZE對內(nèi)存進(jìn)行分類管理的,當(dāng)申請一塊大小為SIZE的內(nèi)存時,分配器就從SIZE集合中分配一個內(nèi)存塊(BLOCK)出去,當(dāng)釋放一個大小為SIZE的內(nèi)存時,則將該內(nèi)存塊放回到原有集合,而不是釋放給操作系統(tǒng)。當(dāng)又要申請相同大小的內(nèi)存時,可以復(fù)用之前被回收的內(nèi)存塊(BLOCK),從而避免了內(nèi)存碎片的產(chǎn)生。[注:因SLAB處理過程的細(xì)節(jié)較多,在此只是做一個原理上的講解]
?
2 總體結(jié)構(gòu)
圖1 SLAB內(nèi)存結(jié)構(gòu)
?
3 處理流程
如圖1中所示:SLAB管理機(jī)制將內(nèi)存大體上分為SLAB頭、SLOT數(shù)組、PAGES數(shù)組、可分配空間、被浪費(fèi)空間等模塊進(jìn)行分別管理,其中各模塊的功能和作用:- SLAB頭:包含SLAB管理的匯總信息,如最小分配單元(min_size)、最小分配單元對應(yīng)的位移(min_shift)、頁數(shù)組地址(pages)、空閑頁鏈表(free)、可分配空間的起始地址(start)、內(nèi)存塊結(jié)束地址(end)等等信息(如代碼1所示),在內(nèi)存的管理過程中,內(nèi)存的分配、回收、定位等等操作都依賴于這些數(shù)據(jù)。
- SLOT數(shù)組:SLOT數(shù)組各成員分別負(fù)責(zé)固定大小的內(nèi)存塊(BLOCK)的分配和回收。在nginx中SLOT[0]~SLOT[7]分別負(fù)責(zé)區(qū)間在[1~8]、[9~16]、[17~32]、[33~64]、[65~128]、[129~256]、[257~512]、[513~1024]字節(jié)大小內(nèi)存的分配,但為方便內(nèi)存塊(BLOCK)的分配和回收,每個內(nèi)存塊(BLOCK)的大小為各區(qū)間的上限(8、16、32、64、128、256、512、1024)。比如說:假如應(yīng)用進(jìn)程請求申請5個字節(jié)的空間,因5處在[1~8]的區(qū)間內(nèi),因此由SLOT[0]負(fù)責(zé)該內(nèi)存的分配,但區(qū)間[1~8]的上限為8,因此即使申請5個字節(jié),卻依然分配8字節(jié)給應(yīng)用進(jìn)程。以此類推:假如申請12字節(jié),12處于區(qū)間[9~16]之間,取上限16,因此由SLOT[1]分配16個字節(jié)給應(yīng)用進(jìn)程;假如申請50字節(jié),50處于區(qū)間[33~64]之間,取上限64,因此由SLOT[2]分配64個字節(jié)給應(yīng)用進(jìn)程;假如申請84字節(jié),84處于區(qū)間[65~128]之間,取上限128,因此由SLOT[3]分配128個字節(jié);...;假如申請722字節(jié),722處于區(qū)間[513~1024]之間,取上限1024,因此由SLOT[7]分配1024字節(jié)。
- PAGES數(shù)組:PAGES數(shù)組各成員分別負(fù)責(zé)可分配空間中各頁的查詢、分配和回收,其處理流程可參考3.2節(jié)的說明。
- 可分配空間:SLAB在邏輯上將可分配空間劃分成M個內(nèi)存頁,每頁大小為4K。每頁內(nèi)存與PAGES數(shù)組成員一一對應(yīng),由PAGES數(shù)組各成員負(fù)責(zé)各內(nèi)存頁的分配和回收。
- 被浪費(fèi)空間:按照每頁4K的大小對空間進(jìn)行劃分時,滿足4K的空間,將作為可分配空間被PAGES數(shù)組進(jìn)行管理,而最后剩余的不足4K的內(nèi)存將會被舍棄,也就是被浪費(fèi)了!
3.1 初始化流程
? 初始化階段主要完成對SLOT頭、SLOT數(shù)組、PAGES數(shù)組、可分配空間和被浪費(fèi)空間的區(qū)域分化,各區(qū)域的劃分可參考圖1和各模塊功能的說明。nginx中slab結(jié)構(gòu)體如下所示:
[cpp]?view plaincopy print?代碼1 SLAB頭部結(jié)構(gòu)體
3.2 頁的管理
3.2.1 頁的分配
1)分配之前
? 在SLAB初始化之后,所有頁可以看成是一個連續(xù)的整體,其內(nèi)存結(jié)構(gòu)如下圖所示:
圖2 頁的結(jié)構(gòu)(分配之前)
2)申請一頁
? 當(dāng)申請一頁時,則將pages[0]從free鏈表中分離出去,如下圖所示:
圖3 頁的結(jié)構(gòu)(申請一頁)
3)申請二頁
? 當(dāng)再申請二頁時,則將page[3]和pages[4]作為一個整體從free鏈表中分離出去,如下圖所示:
圖4 頁的結(jié)構(gòu)(申請二頁)
3.2.2 頁的回收
1)回收一頁
? 當(dāng)頁被回收時,被回收的頁并不會和未被分配的頁進(jìn)行合并,而是通過鏈表串聯(lián)起來,這樣將造成運(yùn)行的時間越長,要申請到超過一頁大小的空間也會變得越來越難。正是因?yàn)檫@個原因,所以slab機(jī)制不適合用來反復(fù)分配和回收超過一頁大小的內(nèi)存空間。如下圖所示:[切記:slab機(jī)制不適合用來反復(fù)分配和回收超過一頁大小的內(nèi)存空間]
圖5 頁的結(jié)構(gòu)(回收一頁)
2)回收二頁
? 當(dāng)頁被回收時,被回收的頁并不會和未被分配的頁進(jìn)行合并,而是通過鏈表串聯(lián)起來,如下圖所示:
圖6 頁的結(jié)構(gòu)(回收二頁)
3.4 SLOT的管理
? SLOT數(shù)組的作用可以參考第三章開頭的闡述。SLOT數(shù)組各成員相當(dāng)于鏈表頭,在SLOT的分配和回收過程中,通過鏈表來組織用于分配各SIZE(1~1024)的PAGE。如,在某時刻,可能存在如下狀態(tài):
圖7? SLOT和PAGES的關(guān)系
3.4.1 頁的管理
1)初始狀態(tài)
? 在SLAB初始化后,slot鏈表頭的下一個節(jié)點(diǎn)都為NULL,如下圖所示:
圖8 SLOT初始狀態(tài)
2)添加一頁
? SLOT[2]負(fù)責(zé)32(17~32)字節(jié)空間的分配和回收,假設(shè)現(xiàn)申請分配24字節(jié)(17~32之間)的空間,因此將從slot[2]中分配。但在初始狀態(tài)下slot[2]的下一頁為NULL,因此需要向頁管理模塊申請一頁pages[x]內(nèi)存,再將該頁加入到slot[2]的鏈表中,添加之后的內(nèi)存結(jié)構(gòu)如下圖所示:
圖9 slot[2]增加一頁
3)暫離鏈表
? SLOT[2]中的每一頁有128(4K/32=128)個單元,當(dāng)一頁分配了128次時,表示該頁可分配單元分配完畢,此時該頁將會暫時從鏈表中剔除出去,以防止下次申請時,做無效的遍歷。如下圖所示:
圖10 slot[2]第一頁被使用完
?
4)再添一頁
? 當(dāng)再次申請17~32字節(jié)時,此時slot[2]的后續(xù)鏈表為空,因此需要再次向頁管理申請一頁pages[y]內(nèi)存,再將該頁加入到slot[2]的鏈表中,如下圖所示。如果該頁又被分配完,則進(jìn)行3)的處理。
圖11 slot[2]再添一頁
5)重入鏈表
? 當(dāng)所有單元被用完的頁pages[x]中的一個單元被回收時,頁pages[x]中將有1個單元可以再次被分配使用,此時應(yīng)該將pages[x]重新加入到slot[2]的鏈表中,以便下次分配時可以從頁pages[x]中進(jìn)行查找。此時內(nèi)存組織形式如下圖所示:
圖12 頁pages[x]重入鏈表
6)回收整頁
? 當(dāng)頁pages[x]所有單元被釋放后,則該頁將會被全部回收:該頁將從slot[2]的鏈表中被剔除,并將頁pages[x]重新加入到free鏈表。此時的內(nèi)存結(jié)構(gòu)圖如下圖所示:
圖13 回收頁pages[x]
?
3.4.2 SLOT的分配
1)頁內(nèi)結(jié)構(gòu)
? 被加入到SLOT數(shù)組鏈表的頁在邏輯上劃分為很多的內(nèi)存單元,每一小內(nèi)存單元的使用情況是通過位圖進(jìn)行標(biāo)記的,1表示被占用,0表示未被占用。如:第20位bit的值為1時,表示第20個內(nèi)存單元被占用。假如此SLOT鏈表的PAGE正好可以劃分為32塊,則其邏輯組織結(jié)構(gòu)如下圖所示:
圖14 PAGE內(nèi)結(jié)構(gòu)
2)分配單元
? 假如此時在SLOT[s]鏈表的頁中連續(xù)申請4個內(nèi)存單元,則其前4個內(nèi)存單元將首先被占用,則此時的位圖結(jié)構(gòu)如下圖所示:
圖15 分配單元
3) 釋放單元
? 假如此時釋放SLOT[s]鏈表頁中第3個內(nèi)存單元,則此時的位圖結(jié)構(gòu)如下圖所示:
圖16 釋放單元
?
轉(zhuǎn)自:"祁峰"的CSDN博客
轉(zhuǎn)載于:https://www.cnblogs.com/zl1991/p/8335908.html
總結(jié)
以上是生活随笔為你收集整理的NGINX原理 之 SLAB分配机制(转)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 成都欢乐谷必玩项目
- 下一篇: 驻马店看男性不育最好的医院推荐