內存碎片的產生與對數據進行的操作,數據的特點等有關,與使用的內存分配器也有關。如果redis服務器的內存碎片很大,可以通過安全重啟的方式減少內存碎片,重啟后,redis重新從備份文件中讀取數據,在內存中進行重排,為每個數據重新選擇合適的內存單元,減少內存碎片
linux采用著名的伙伴系統buddy system算法來解決外碎片問題。把所有的空閑頁框分組為11個塊鏈表,每個鏈表分別包含大小為1,2,4,8,16,32,64,128,256,512,1024連續的頁框,對1024頁框的最大請求對應著4MB大小的連續RAM(每頁大小為4KB),每個塊的第一個頁框的物理地址是該塊大小的整數倍,例如,大小為16個頁框的塊,其起始地址是16*2^12的倍數。
我們通過一個例子來說明伙伴算法的工作原理,假設現在要請求一個256個頁框的塊(1MB),算法步驟如下:
- 在256頁框的鏈表中檢查是否有一個空閑塊,如果沒有,查找下一個更大的塊,如果有,請求滿足。
- 在512頁框的鏈表中檢查是否有一個空閑塊,如果有,把512個頁框的空閑塊分為兩份,第一份用于滿足請求,第二份鏈接到256個頁框的鏈表中。如果沒有空閑塊,繼續尋找下一個更大的塊。
下圖比較形象地描述了該過程。
以上過程的逆過程,就是頁框塊的釋放過程,也是該算法名字的由來,內核試圖把大小為B的一對空閑伙伴塊合并為一個2B的單獨塊,滿足以下條件的兩個塊稱之為伙伴:
- 兩個塊具有相同的大小
- 他們的物理地址是連續的
- 第一塊的第一個頁框的物理地址是2 * B * 2^12
該算法是遞歸的,如果它成功合并了B,就會試圖去合并2B,以再次試圖形成更大的塊。