NGINX原理 之 SLAB分配機制(轉)

1 引言

? 眾所周知,操作系統使用伙伴系統管理內存,不僅會造成大量的內存碎片,同時處理效率也較低下。SLAB是一種內存管理機制,其擁有較高的處理效率,同時也有效的避免內存碎片的產生,其核心思想是預分配。其按照SIZE對內存進行分類管理的,當申請一塊大小為SIZE的內存時,分配器就從SIZE集合中分配一個內存塊(BLOCK)出去,當釋放一個大小為SIZE的內存時,則將該內存塊放回到原有集合,而不是釋放給操作系統。當又要申請相同大小的內存時,可以復用之前被回收的內存塊(BLOCK),從而避免了內存碎片的產生。[注:因SLAB處理過程的細節較多,在此只是做一個原理上的講解]

?

2 總體結構

圖1 SLAB內存結構

?

3 處理流程

如圖1中所示:SLAB管理機制將內存大體上分為SLAB頭、SLOT數組、PAGES數組、可分配空間、被浪費空間等模塊進行分別管理,其中各模塊的功能和作用:
  • SLAB頭:包含SLAB管理的匯總信息,如最小分配單元(min_size)、最小分配單元對應的位移(min_shift)、頁數組地址(pages)、空閑頁鏈表(free)、可分配空間的起始地址(start)、內存塊結束地址(end)等等信息(如代碼1所示),在內存的管理過程中,內存的分配、回收、定位等等操作都依賴于這些數據。
  • SLOT數組:SLOT數組各成員分別負責固定大小的內存塊(BLOCK)的分配和回收。在nginx中SLOT[0]~SLOT[7]分別負責區間在[1~8]、[9~16]、[17~32]、[33~64]、[65~128]、[129~256]、[257~512]、[513~1024]字節大小內存的分配,但為方便內存塊(BLOCK)的分配和回收,每個內存塊(BLOCK)的大小為各區間的上限(8、16、32、64、128、256、512、1024)。比如說:假如應用進程請求申請5個字節的空間,因5處在[1~8]的區間內,因此由SLOT[0]負責該內存的分配,但區間[1~8]的上限為8,因此即使申請5個字節,卻依然分配8字節給應用進程。以此類推:假如申請12字節,12處于區間[9~16]之間,取上限16,因此由SLOT[1]分配16個字節給應用進程;假如申請50字節,50處于區間[33~64]之間,取上限64,因此由SLOT[2]分配64個字節給應用進程;假如申請84字節,84處于區間[65~128]之間,取上限128,因此由SLOT[3]分配128個字節;...;假如申請722字節,722處于區間[513~1024]之間,取上限1024,因此由SLOT[7]分配1024字節。
  • PAGES數組:PAGES數組各成員分別負責可分配空間中各頁的查詢、分配和回收,其處理流程可參考3.2節的說明。
  • 可分配空間:SLAB在邏輯上將可分配空間劃分成M個內存頁,每頁大小為4K。每頁內存與PAGES數組成員一一對應,由PAGES數組各成員負責各內存頁的分配和回收。
  • 被浪費空間:按照每頁4K的大小對空間進行劃分時,滿足4K的空間,將作為可分配空間被PAGES數組進行管理,而最后剩余的不足4K的內存將會被舍棄,也就是被浪費了!

3.1 初始化流程

? 初始化階段主要完成對SLOT頭、SLOT數組、PAGES數組、可分配空間和被浪費空間的區域分化,各區域的劃分可參考圖1和各模塊功能的說明。nginx中slab結構體如下所示:

[cpp]?view plaincopy
print?
  1. typedef?struct?{??
  2. ????size_t????????????min_size;?????/*?最小分配單元?*/??
  3. ????size_t????????????min_shift;????/*?最小分配單元對應的位移?*/??
  4. ??
  5. ????ngx_slab_page_t??*pages;????????/*?頁數組?*/??
  6. ????ngx_slab_page_t???free;?????????/*?空閑頁鏈表?*/??
  7. ??
  8. ????u_char???????????*start;????????/*?可分配空間的起始地址?*/??
  9. ????u_char???????????*end;??????????/*?內存塊的結束地址?*/??
  10. ??
  11. ????...?????????????????????????????/*?其他變量成員(省略)?*/??
  12. }ngx_slab_pool_t??

代碼1 SLAB頭部結構體

3.2 頁的管理

3.2.1 頁的分配

1)分配之前

? 在SLAB初始化之后,所有頁可以看成是一個連續的整體,其內存結構如下圖所示:

圖2 頁的結構(分配之前)

2)申請一頁

? 當申請一頁時,則將pages[0]從free鏈表中分離出去,如下圖所示:

圖3 頁的結構(申請一頁)

3)申請二頁

? 當再申請二頁時,則將page[3]和pages[4]作為一個整體從free鏈表中分離出去,如下圖所示:

圖4 頁的結構(申請二頁)

3.2.2 頁的回收

1)回收一頁

? 當頁被回收時,被回收的頁并不會和未被分配的頁進行合并,而是通過鏈表串聯起來,這樣將造成運行的時間越長,要申請到超過一頁大小的空間也會變得越來越難。正是因為這個原因,所以slab機制不適合用來反復分配和回收超過一頁大小的內存空間。如下圖所示:[切記:slab機制不適合用來反復分配和回收超過一頁大小的內存空間]

圖5 頁的結構(回收一頁)

2)回收二頁

? 當頁被回收時,被回收的頁并不會和未被分配的頁進行合并,而是通過鏈表串聯起來,如下圖所示:

圖6 頁的結構(回收二頁)

3.4 SLOT的管理

? SLOT數組的作用可以參考第三章開頭的闡述。SLOT數組各成員相當于鏈表頭,在SLOT的分配和回收過程中,通過鏈表來組織用于分配各SIZE(1~1024)的PAGE。如,在某時刻,可能存在如下狀態:

圖7? SLOT和PAGES的關系

3.4.1 頁的管理

1)初始狀態

? 在SLAB初始化后,slot鏈表頭的下一個節點都為NULL,如下圖所示:

圖8 SLOT初始狀態

2)添加一頁

? SLOT[2]負責32(17~32)字節空間的分配和回收,假設現申請分配24字節(17~32之間)的空間,因此將從slot[2]中分配。但在初始狀態下slot[2]的下一頁為NULL,因此需要向頁管理模塊申請一頁pages[x]內存,再將該頁加入到slot[2]的鏈表中,添加之后的內存結構如下圖所示:

圖9 slot[2]增加一頁

3)暫離鏈表

? SLOT[2]中的每一頁有128(4K/32=128)個單元,當一頁分配了128次時,表示該頁可分配單元分配完畢,此時該頁將會暫時從鏈表中剔除出去,以防止下次申請時,做無效的遍歷。如下圖所示:

圖10 slot[2]第一頁被使用完

?

4)再添一頁

? 當再次申請17~32字節時,此時slot[2]的后續鏈表為空,因此需要再次向頁管理申請一頁pages[y]內存,再將該頁加入到slot[2]的鏈表中,如下圖所示。如果該頁又被分配完,則進行3)的處理。

圖11 slot[2]再添一頁

5)重入鏈表

? 當所有單元被用完的頁pages[x]中的一個單元被回收時,頁pages[x]中將有1個單元可以再次被分配使用,此時應該將pages[x]重新加入到slot[2]的鏈表中,以便下次分配時可以從頁pages[x]中進行查找。此時內存組織形式如下圖所示:

圖12 頁pages[x]重入鏈表

6)回收整頁

? 當頁pages[x]所有單元被釋放后,則該頁將會被全部回收:該頁將從slot[2]的鏈表中被剔除,并將頁pages[x]重新加入到free鏈表。此時的內存結構圖如下圖所示:

圖13 回收頁pages[x]

?

3.4.2 SLOT的分配

1)頁內結構

? 被加入到SLOT數組鏈表的頁在邏輯上劃分為很多的內存單元,每一小內存單元的使用情況是通過位圖進行標記的,1表示被占用,0表示未被占用。如:第20位bit的值為1時,表示第20個內存單元被占用。假如此SLOT鏈表的PAGE正好可以劃分為32塊,則其邏輯組織結構如下圖所示:

圖14 PAGE內結構

2)分配單元

? 假如此時在SLOT[s]鏈表的頁中連續申請4個內存單元,則其前4個內存單元將首先被占用,則此時的位圖結構如下圖所示:

圖15 分配單元

3) 釋放單元

? 假如此時釋放SLOT[s]鏈表頁中第3個內存單元,則此時的位圖結構如下圖所示:

圖16 釋放單元

?

轉自:"祁峰"的CSDN博客

轉載于:https://www.cnblogs.com/zl1991/p/8335908.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/390309.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/390309.shtml
英文地址,請注明出處:http://en.pswp.cn/news/390309.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

apk之間數據共享的方式

1、四大組件之ContentProvider大法2、shareUserId3、apk均去遠端獲取配置文件(或接口)4、AIDL(bindService)5、SharePreference設置為MODE_WORLD_READABLE|MODE_WORLD_WRITEABLE模式,由于存在安全問題,已被…

藍橋杯java 基礎練習 十六進制轉十進制

問題描述從鍵盤輸入一個不超過8位的正的十六進制數字符串,將它轉換為正的十進制數后輸出。注:十六進制數中的10~15分別用大寫的英文字母A、B、C、D、E、F表示。樣例輸入FFFF樣例輸出65535import java.math.BigInteger; import java.util.Scanner;public …

dynamic web module消失不見

2019獨角獸企業重金招聘Python工程師標準>>> 方法1:在project Facets選項中勾選Dynamic Web Module即可 方法2: 我用eclipse對項目進行修改名稱,修改成功后。項目就沒有Deployment Descriptor(如下圖紅色框中&#xff…

576. 出界的路徑數

576. 出界的路徑數 給你一個大小為 m x n 的網格和一個球。球的起始坐標為 [startRow, startColumn] 。你可以將球移到在四個方向上相鄰的單元格內(可以穿過網格邊界到達網格之外)。你 最多 可以移動 maxMove 次球。 給你五個整數 m、n、maxMove、star…

telnet命令發送郵件

下面的例子是用qq的smtp服務器。 set localecho 本地回顯啟用 telnet smtp.qq.com 25 220 smtp.qq.com Esmtp QQ Mail Server helo sis 250 smtp.qq.com//服務器返回250 smtp.qq.com STARTTLS 220 Ready to start TLS//服務器返回 220 準備開啟TLS通訊 auth login 334 VXNlcm5h…

myelcipse和maven搭建項目

偷懶一下,完了補充 轉載:https://www.cnblogs.com/jr1260/p/6438811.html https://www.cnblogs.com/yangmingyu/p/6908519.html https://www.cnblogs.com/henuyuxiang/p/6288476.html 轉載于:https://www.cnblogs.com/0914lx/p/8342343.html

551. 學生出勤記錄

551. 學生出勤記錄 I 給你一個字符串 s 表示一個學生的出勤記錄,其中的每個字符用來標記當天的出勤情況(缺勤、遲到、到場)。記錄中只含下面三種字符: ‘A’:Absent,缺勤 ‘L’:Late&#xff…

JavaScript實現職責鏈模式

什么是職責鏈模式 職責鏈模式的定義是:使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關系,將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。舉個例子:當你從…

Metrics介紹和Spring的集成

參考: http://colobu.com/2014/08/08/Metrics-and-Spring-Integration/ https://www.cnblogs.com/yangecnu/p/Using-Metrics-to-Profiling-WebService-Performance.html

配置 aws cli_AWS CLI教程–如何安裝,配置和使用AWS CLI了解您的資源環境

配置 aws cliHow to get exactly the account and environment information you need to manage your AWS account using just the AWS CLI如何僅使用AWS CLI準確獲取管理AWS賬戶所需的賬戶和環境信息 Installing the AWS CLI is actually quite simple. The best way to get …

grep遞歸查找頭文件_Grep命令教程–如何使用遞歸查找在Linux和Unix中搜索文件

grep遞歸查找頭文件grep stands for Globally Search For Regular Expression and Print out. It is a command line tool used in UNIX and Linux systems to search a specified pattern in a file or group of files. grep代表全局搜索正則表達式并打印出來 。 它是UNIX和Li…

C++ 前置聲明

(一)class的前置聲明 class的前置聲明有兩種。 pre.hclass PreA {}; main.hclass PreA; class Main {};//或者 class Main {class PreA* A; }; (二) struct前置聲明 struct的前置聲明只能用第一種。 (三) 有typedef的前置聲明 Pr…

2.18 特殊權限set_uid 2.19 特殊權限set_gid 2.20 特殊權限stick_bit 2.21 軟鏈接文件 2.22 硬連接文件...

2019獨角獸企業重金招聘Python工程師標準>>> 特殊權限set_uid set_uid:該權限針對二進制可執行文件,使文件在執行階段具有文件所有者的權限; 通俗一點講就是,普通用戶想要訪問一個沒有其他用戶可執行權限的目錄時,暫時…

345. 反轉字符串中的元音字母

345. 反轉字符串中的元音字母 給你一個字符串 s ,僅反轉字符串中的所有元音字母,并返回結果字符串。 元音字母包括 ‘a’、‘e’、‘i’、‘o’、‘u’,且可能以大小寫兩種形式出現。 示例 1: 輸入:s “hello” 輸…

通過制作數字桌面游戲和Web應用程序學習JavaScript

Building 2D games can be a great way to learn JavaScript, especially when working through the basics of complex tabletop game logic.制作2D游戲可能是學習JavaScript的好方法,尤其是在研究復雜的桌面游戲邏輯基礎時。 In this series, I’m going to intr…

【HAVENT原創】Node Express API 通用配置

為什么80%的碼農都做不了架構師?>>> ( 基于 Express 4.x ) 啟動文件 /app.js: var express require(express); var bodyParser require(body-parser); var proxy require(http-proxy-middleware); var path require(path);var index re…

C#使用Json.NET解析Json

本文轉載自 http://xiaosheng.me/2016/10/01/article25/ 最近在 C# 項目中需要使用到 Json 格式的數據,我簡單上網搜索了一下,基本上有兩種操作 Json 數據的方法: 使用 Windows 系統自帶的類使用第三方的包本著“第三方包一定有比系統自帶類優…

現在JavaScript日期–如何在JavaScript中獲取當前日期

Many applications you build will have some sort of a date component, whether its the creation date of a resource, or the timestamp of an activity. 您構建的許多應用程序都將具有某種日期組件,無論是資源的創建日期還是活動的時間戳。 Dealing with date…

233. 數字 1 的個數

給定一個整數 n,計算所有小于等于 n 的非負整數中數字 1 出現的個數。 示例 1: 輸入:n 13 輸出:6 示例 2: 輸入:n 0 輸出:0 解題思路 正確性證明 例如:對于n3015&#xff0c…

Linux串口設置參數

為什么80%的碼農都做不了架構師?>>> 在Linux環境下,串口名從ttyS0開始依次是ttyS1、ttyS2等。在本程序中,使用ttyS0作為通信串口。在打開ttyS0的時候選項 O_NOCTTY 表示不能把本串口當成控制終端,否則用戶的鍵盤輸入信…