嵌入式100題(017) malloc的底層實現

2022-06-09 15:36:11 字數 1825 閱讀 1826

使用過c語言的都知道malloc是乙個動態分配記憶體的函式,還可以通過free釋放記憶體空間。

如果我們想分析一下malloc的原始碼,這其實不是一會就能看懂的,但是我們可以討論一下malloc的簡單實現。

在這之前,我們先來看一下虛擬記憶體空間。

虛擬記憶體空間是作業系統實現記憶體管理的一種機制。作業系統為每個程序維護乙個虛擬記憶體空間。作業系統會將虛擬記憶體和實際的物理記憶體進行對映,cpu晶元上叫做儲存器管理單元(memory management unit,mmu)的專用硬體,利用存放在主存中的查詢表來動態翻譯虛擬位址,該錶的內容是由作業系統管理。虛擬記憶體使得使用者感覺記憶體空間時連續的,同時給程序提供獨佔記憶體的假象。

我們可以看到虛擬記憶體空間的頂部是核心管理的記憶體空間,下面則是使用者的記憶體空間,使用者空間無權訪問核心的記憶體空間。

我們可以看到乙個區域,執行時堆。我們可以看到執行時堆上面還有一塊黑色部分,這就是還未對映的記憶體。

在已經對映的記憶體空間結尾有乙個break指標,這個指標下面是對映好的記憶體,可以訪問,上面則是未對映的訪問,不能訪問。可以通過系統呼叫sbrk(位移量)移動brk指標的位置,同時返回brk指標的位置,達到申請記憶體的目。brk(void *addr)系統呼叫可以直接將brk設定為某個位址,成功返回0,不成功返回-1。而rlimit則是限制程序堆記憶體容量的指標。

在作業系統角度來看,分配記憶體有兩種方式,一種是採用推進brk指標來增加堆的有效區域來申請記憶體空間,還有一種是採用mmap是在程序的虛擬位址空間中(堆和棧中間,稱為檔案對映區域的地方)找一塊空閒的虛擬記憶體。這兩種方式都是分配虛擬記憶體,只有當第一次訪問虛擬位址空間時,作業系統給分配物理記憶體空間。

malloc是採用brk的方式來動態分配記憶體。

那麼來談一下空間內配的實現問題:

其中一種是隱式鍊錶,實際上是陣列,malloc分配空間必然有乙個資料結構,允許它來區分邊界,區分已分配和空閒的空間,資料結構中包含乙個頭部資訊和有效載荷,有效載荷的首位址就是malloc返回的位址,可能在尾部還有填充,為了保持記憶體對齊。頭部相當於該資料結構的元資料,其中包含了塊大小和是否是空閒空間的資訊,這樣可以根據頭位址和塊大小的位址推出下乙個記憶體塊的位址,這就是隱式鍊錶。

malloc記憶體分配原理:

malloc基本的實現原理就是維護乙個記憶體空閒鍊錶,當申請記憶體空間時,搜尋記憶體空閒鍊錶,找到適配的空閒記憶體空間,然後將空間分割成兩個記憶體塊,乙個變成分配塊,乙個變成新的空閒塊。如果沒有搜尋到,那麼就會用sbrk()才推進brk指標來申請記憶體空間。

搜尋空閒塊最常見的演算法有:首次適配,下一次適配,最佳適配。

首次適配:第一次找到足夠大的記憶體塊就分配,這種方法會產生很多的記憶體碎片。

下一次適配:也就是說等第二次找到足夠大的記憶體塊就分配,這樣會產生比較少的記憶體碎片。

最佳適配:對堆進行徹底的搜尋,從頭開始,遍歷所有塊,使用資料區大小大於size且差值最小的塊作為此次分配的塊。

合併空閒塊:

在釋放記憶體塊後,如果不進行合併,那麼相鄰的空閒記憶體塊還是相當於兩個記憶體塊,會形成一種假碎片。所以當釋放記憶體後,我們需要將兩個相鄰的記憶體塊進行合併。

顯式空閒鍊錶:

還有一種實現方式則是採用顯示空閒鍊錶,這個是真正的鍊錶形式。在之前的有效載荷中加入了之前前驅和後驅的指標,也可以稱為雙向鍊錶。維護空閒鍊錶的的方式第一種是用後進先出(lifo),將新釋放的塊放置在鍊錶的開始處。另一種方法是按照位址的順序來維護。

嵌入式100題(017) malloc的底層實現

使用過c語言的都知道malloc是乙個動態分配記憶體的函式,還可以通過free釋放記憶體空間。如果我們想分析一下malloc的原始碼,這其實不是一會就能看懂的,但是我們可以討論一下malloc的簡單實現。在這之前,我們先來看一下虛擬記憶體空間。虛擬記憶體空間是作業系統實現記憶體管理的一種機制。作業系...

嵌入式100題(48) 氣泡排序

氣泡排序 氣泡排序就是把小的元素往前調或者把大的元素往後調。比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。所以,如果兩個元素相等,我想你是不會再無聊地把他們倆交換一下的 如果兩個相等的元素沒有相鄰,那麼即使通過前面的兩兩交換把兩個相鄰起來,這時候也不會交換,所以相同元素的前後順序並沒有改變,...

嵌入式100題(51) 歸併排序

歸併排序 歸併排序是把序列遞迴地分成短序列,遞迴出口是短序列只有1個元素 認為直接有序 或者2個序列 1次比較和交換 然後把各個有序的段序列合併成乙個有序的長序列,不斷合併直到原序列全部排好序。可以發現,在1個或2個元素時,1個元素不會交換,2個元素如果大小相等也沒有人故意交換,這不會破壞穩定性。那...