使用過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指標來申請記憶體空間。
合併空閒塊
在釋放記憶體塊後,如果不進行合併,那麼相鄰的空閒記憶體塊還是相當於兩個記憶體塊,會形成一種假碎片。所以當釋放記憶體後,我們需要將兩個相鄰的記憶體塊進行合併。
顯式空閒鍊錶
還有一種實現方式則是採用顯示空閒鍊錶,這個是真正的鍊錶形式。在之前的有效載荷中加入了之前前驅和後驅的指標,也可以稱為雙向鍊錶。維護空閒鍊錶的的方式第一種是用後進先出(lifo),將新釋放的塊放置在鍊錶的開始處。另一種方法是按照位址的順序來維護。
malloc底層實現
1.結論 2.背景 3.分配原理 4.具體情況 1 malloc 小於128k的記憶體時,使用brk系統呼叫在堆上申請記憶體 2 malloc 大於128k的記憶體時,使用mmap系統呼叫在棧與堆之間的對映區分配記憶體 1.結論 1 當開闢的空間小於 128k 時,呼叫 brk 函式,malloc ...
malloc底層實現
linux維護乙個break指標,這個指標指向堆空間某個位置。從堆起始位址到break之間的位址空間為對映好的,可以供程序訪問 而從break往上,是未對映的位址空間,如果訪問這段空間則程式會報錯。我們使用malloc進行記憶體分配就是從break往上進行的 而rlimit則是限制程序堆記憶體容量的...
malloc的底層實現
每個程序都有乙個虛擬記憶體空間,虛擬記憶體空間通過mmu 儲存器管理單元 對映到真正的物理空間,mmu是乙個硬體,利用儲存在主存中的查詢表翻譯虛擬位址,查詢表由作業系統管理,使用者無法獲取。虛擬位址空間給每個程序乙個假象,就像每個進城擁有4g的執行空間一樣,但是實際在使用記憶體的時候,虛擬位址空間通...