malloc的基本實現

2021-08-13 09:44:09 字數 3569 閱讀 4788

一直對malloc的實現不是很懂,k&r的c程式語言的8.7節講了乙個malloc的基本實現,這篇文章主要把自己的理解記錄一下。

malloc是在堆裡申請空間的,每一次申請的空間叫做記憶體塊,每個記憶體塊包括頭部和資料區,空閒的記憶體塊通過乙個迴圈鍊錶組織在一起,記憶體塊的位址是從低到高排列的,這是由堆的位址是從低到高生長決定的,鍊錶有乙個表頭,表頭不包含資料區。

為了簡化塊的對齊,每個記憶體塊的大小都是頭部的整數倍,頭部通過乙個聯合體來實現,包括指向下乙個塊的指標和當前塊的長度:

typedef long align;/*for alignment to long boundary*/

union header s;

align x; //強制塊的對齊

};typedef union header header;

當第一次使用

malloc

時,首先讓

base

指向自己

申請空間時遍歷每乙個空閒記憶體塊,這裡分為

3種情況: 1)

當申請的空間剛好為塊的長度時,返回該塊的資料區位址,並把塊從鍊錶中移除 2)

當申請的空間小於塊的長度時,從尾部**乙個資料塊,並將資料區位址返回給使用者

3)    

當遍歷完整個鍊錶後,不存在記憶體塊滿足申請時,那麼呼叫

morecore()

向作業系統申請乙個更大的記憶體塊插入到記憶體中,實現**如下:

static header base;  //煉表表頭

static header *freep = null; //空閒鍊錶的初始指標

void *malloc(unsigned nbytes)

//從freep的下乙個記憶體塊開始遍歷鍊錶

for(p = prevp->s.ptr; ;prevp = p, p= p->s.ptr)

freep = prevp;

return (void*)(p+1);//返回資料區

}if ((p = morecore(nunits)) == null)//向作業系統申請空間

return null; /* none left */}}

為了講解

morecore

的實現,首先簡單介紹一下作業系統的記憶體排布,這個主要摘自以下文章

「根據linux

核心相關文件

描述,linux64

位作業系統僅使用低

47位,高

17位做擴充套件(只能是全0或全

1)。所以,實際用到的位址為空間為

0x0000000000000000 ~ 0x00007fffffffffff

和0xffff800000000000 ~ 0xffffffffffffffff

,其中前面為使用者空間(

user space

),後者為核心空間(

kernel space

)。圖示如下:

對使用者來說,主要關注的空間是

user space

。將user space

放大後,可以看到裡面主要分為如下幾段:

一般來說,

malloc

所申請的記憶體主要從

heap

區域分配(本文不考慮通過

mmap

申請大塊記憶體的情況)。程序所面對的虛擬記憶體位址空間,只有按頁對映到物理記憶體位址,才能真正使用。受物理儲存容量限制,整個堆虛擬記憶體空間不可能全部對映到實際的物理記憶體。

linux

對堆的管理示意如下:

維護乙個

break

指標,這個指標指向堆空間的某個位址。從堆起始位址到

break

之間的位址空間為對映好的,可以供程序訪問;而從

break

往上,是未對映的位址空間,如果訪問這段空間則程式會報錯。

要增加乙個程序實際的可用堆大小,就需要將

break

指標向高位址移動。

linux

通過brk

和sbrk

系統呼叫操作

break

指標。兩個系統呼叫的原型如下:

int brk(void *addr);

void *sbrk(intptr_t increment);

brk將

break

指標直接設定為某個位址,而

sbrk

將break

從當前位置移動

increment

所指定的增量。

brk在執行成功時返回

0,否則返回

-1並設定

errno

為enomem

;sbrk

成功時返回

break

移動之前所指向的位址,否則返回

(void *)-1。

乙個小技巧是,如果將

increment

設定為0

,則可以獲得當前

break

的位址。」

通過上面的講解之後,我們知道向作業系統請求記憶體塊其實就是移動

break

指標,但這是乙個開銷很大的操作,我們不希望每次都呼叫

morecore

函式,基於這個考慮

morecore

函式請求至少

nalloc

個header

單元長度,這個較大的塊將根據需要分成多個較小的塊

#define nalloc 0//1024    /* minimum #units to request */

static header *morecore(unsigned nu)

最後分析

free

函式的實現,由上面

sbrk

的實現可知記憶體塊的位址是從低到高排列的,我們定義最低的位址為鍊錶的開始,最高的位址為鍊錶的末尾,在

free

函式中會遍歷鍊錶確定要釋放的位址處於哪兩個相鄰的空閒塊之間,也可能處於鍊錶的末尾,找到後將其插入到這兩個空閒塊之間,如果被釋放的塊與空閒塊相鄰,那麼將其與空閒塊合併。

void free(void *ap)

else

bp->s.ptr = p->s.ptr;

if (p+p->s.size == bp) else

p->s.ptr = bp;

freep = p;//返回前乙個相鄰的空閒塊

}

這是malloc

的乙個簡單實現,以後可能會回來再看看

glibc和vs

裡的實現

malloc的實現原理

malloc 是 c語言中動態 儲存管理 的一組標準庫函式之一。其作用是在記憶體的動態儲存區中分配乙個長度為size的連續空間。其引數是乙個無符號整形數,返回值是乙個指向所分配的連續儲存域的起始位址的指標。動態記憶體分配 就 是指在程式執行的過程中動態地分配或者 儲存空間的分配記憶體的方法。動態記憶...

malloc的底層實現

每個程序都有乙個虛擬記憶體空間,虛擬記憶體空間通過mmu 儲存器管理單元 對映到真正的物理空間,mmu是乙個硬體,利用儲存在主存中的查詢表翻譯虛擬位址,查詢表由作業系統管理,使用者無法獲取。虛擬位址空間給每個程序乙個假象,就像每個進城擁有4g的執行空間一樣,但是實際在使用記憶體的時候,虛擬位址空間通...

malloc的實現原理

malloc是c語言最常用的標準庫函式之一,用於在程式執行中動態地申請記憶體空間。我們都會使用它,其函式原型為 extern void malloc unsigned int num bytes 那麼它是怎麼實現的呢?不同的編譯環境中對它的實現可能不同。比如glibc the gnu c libra...