malloc底層實現

2021-09-24 16:15:14 字數 2882 閱讀 1431

1.結論

2.背景

3.分配原理

4.具體情況

(1)malloc()小於128k的記憶體時,使用brk系統呼叫在堆上申請記憶體

(2)malloc()大於128k的記憶體時,使用mmap系統呼叫在棧與堆之間的對映區分配記憶體

1.結論:

1)當開闢的空間小於 128k 時,呼叫 brk()函式,malloc 的底層實現是系統呼叫函式 brk(),其主要移動指標 _enddata(此時的 _enddata 指的是 linux 位址空間中堆段的末尾位址,不是資料段的末尾位址)

2)當開闢的空間大於 128k 時,mmap()系統呼叫函式來在虛擬位址空間中(堆和棧中間,稱為「檔案對映區域」的地方)找一塊空間來開闢。

2.背景:

當乙個程序發生缺頁中斷的時候,程序會陷入核心態,執行以下操作:

1)檢查要訪問的虛擬位址是否合法

2)查詢/分配乙個物理頁

3)填充物理頁內容(讀取磁碟,或者直接置0,或者什麼都不做)

4)建立對映關係(虛擬位址到實體地址的對映關係)

5)重複執行發生缺頁中斷的那條指令

如果第3布,需要讀取磁碟,那麼這次缺頁就是 majfit(major fault:大錯誤),否則就是 minflt(minor fault:小錯誤)

可通過以下命令檢視缺頁中斷資訊

ps -o majflt,minflt -c

ps -o majflt,minflt -p

其中, majflt 代表 major fault ,指大錯誤, minflt 代表 minor fault ,指小錯誤。這兩個數值表示乙個程序自啟動以來所發生的缺頁中斷的次數。

其中 majflt 與 minflt 的不同是, majflt 表示需要讀寫磁碟,可能是記憶體對應頁面在磁碟中需要 load 到物理記憶體中,也可能是此時物理記憶體不足,需要淘汰部分物理頁面至磁碟中。

3.分配原理:

從作業系統角度看,程序分配記憶體有兩種方式,分別由兩個系統呼叫完成:brk 和 mmap (不考慮共享記憶體)

1)brk 是將堆最小位址(.data)的指標 _edata 往高位址推

2)mmap 是在程序的虛擬位址空間中(堆和棧中間,稱為「檔案對映區域」的地方)找一塊空閒的虛擬記憶體。

這兩種方式分配的都是虛擬記憶體,沒有分配物理記憶體。在第一次訪問已分配的虛擬位址空間的時候,發生缺頁中斷,作業系統負責分配物理記憶體,然後建立虛擬記憶體和物理記憶體之間的對映關係。

(1)情況一:malloc 小於 128k 的記憶體,使用 brk 分配

1,程序啟動的時候,其(虛擬)記憶體空間的初始布局如圖1所示

2,程序呼叫a=malloc(30k)以後,記憶體空間如圖2:

malloc函式會呼叫brk系統呼叫,將_edata指標往高位址推30k,就完成虛擬記憶體分配

你可能會問:難道這樣就完成記憶體分配了?

事實是:_edata+30k只是完成虛擬位址的分配,a這塊記憶體現在還是沒有物理頁與之對應的,等到程序第一次讀寫a這塊記憶體的時候,發生缺頁中斷,這個時候,核心才分配a這塊記憶體對應的物理頁。也就是說,如果用malloc分配了a這塊內容,然後從來不訪問它,那麼,a對應的物理頁是不會被分配的。

3,程序呼叫b=malloc(40k)以後,記憶體空間如圖3

(2)malloc 大於 128k 的記憶體,使用 mmap 分配(munmap 釋放)

程序呼叫c=malloc(200k)以後,記憶體空間如圖4

預設情況下,malloc函式分配記憶體,如果請求記憶體大於128k(可由m_mmap_threshold選項調節),那就不是去推_edata指標了,而是利用mmap系統呼叫,從堆和棧的中間分配一塊虛擬記憶體

這樣子做主要是因為:

brk分配的記憶體需要等到高位址記憶體釋放以後才能釋放(例如,在b釋放之前,a是不可能釋放的,因為只有乙個_edata 指標,這就是記憶體碎片產生的原因,什麼時候緊縮看下面),而mmap分配的記憶體可以單獨釋放。

當然,還有其它的好處,也有壞處,再具體下去,有興趣的同學可以去看glibc裡面malloc的**了。

5,程序呼叫d=malloc(100k)以後,記憶體空間如圖5

6,程序呼叫free(c)以後,c對應的虛擬記憶體和物理記憶體一起釋放

7,程序呼叫free(b)以後,如圖7所示

b對應的虛擬記憶體和物理記憶體都沒有釋放,因為只有乙個_edata指標,如果往回推,那麼d這塊記憶體怎麼辦呢當然,b這塊記憶體,是可以重用的,如果這個時候再來乙個40k的請求,那麼malloc很可能就把b這塊記憶體返回回去了

8,程序呼叫free(d)以後,如圖8所示

b和d連線起來,變成一塊140k的空閒記憶體

9,預設情況下:

當最高位址空間的空閒記憶體超過128k(可由m_trim_threshold選項調節)時,執行記憶體緊縮操作(trim)。在上乙個步驟free的時候,發現最高位址空閒記憶體超過128k,於是記憶體緊縮,變成圖9所示

malloc底層實現

linux維護乙個break指標,這個指標指向堆空間某個位置。從堆起始位址到break之間的位址空間為對映好的,可以供程序訪問 而從break往上,是未對映的位址空間,如果訪問這段空間則程式會報錯。我們使用malloc進行記憶體分配就是從break往上進行的 而rlimit則是限制程序堆記憶體容量的...

malloc的底層實現

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

malloc 底層原理實現

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