c語言 malloc函式詳解

2021-08-21 20:02:25 字數 3412 閱讀 7153

談到malloc函式相信學過c語言的人都很熟悉,但是malloc底層到底做了什麼又有多少人知道。

1、關於malloc相關的幾個函式

關於malloc我們進入linux man一下就會得到如下結果:

也可以這樣認為(window下)原型:

extern

void *malloc(unsigned

int num_bytes);

標頭檔案:

#include或者#include兩者的內容是完全一樣的
如果分配成功:則返回指向被分配記憶體空間的指標

不然返回指標null

同時,當記憶體不再使用的時候,應使用free()函式將記憶體塊釋放掉。

關於:void*,表示未確定型別的指標,c,c++規定void*可以強轉為任何其他型別的指標,關於void還有一種說法就是其他任何型別都可以直接賦值給它,無需進行強轉,但是反過來不可以

malloc:

malloc分配的記憶體大小至少為引數所指定的位元組數

malloc的返回值是乙個指標,指向一段可用記憶體的起始位置,指向一段可用記憶體的起始位址,多次呼叫malloc所分配的位址不能有重疊部分,除非某次malloc所分配的位址被釋放掉malloc應該盡快完成記憶體分配並返回(不能使用np-hard的記憶體分配演算法)實現malloc時應同時實現記憶體大小調整和記憶體釋放函式(realloc和free)

malloc和free是配對的,如果申請後不釋放就是記憶體洩露,如果無故釋放那就是什麼也沒做,釋放只能釋放一次,如果一塊空間釋放兩次或者兩次以上會出現錯誤(但是釋放空指標例外,釋放空指標也等於什麼也沒做,所以釋放多少次都是可以的。)

2、malloc和new

new返回指定型別的指標,並且可以自動計算所需要的大小。

int

*p;p = new int;//返回型別為int* ,分配的大小是sizeof(int)

p = new int[100];//返回型別是int

*型別,分配的大小為sizeof(int)*100

而malloc需要我們自己計算位元組數,並且返回的時候要強轉成指定型別的指標。

int *p;

p = (int *)malloc(sizeof(int));

int brk(void *addr);

void *sbrk(inptr_t increment);

brk將break指標直接設定為某個位址,而sbrk將break從當前位置移動increment所指定的增量。brk在執行成功時返回0,否則返回-1並設定為errno為enomem,sbrk成功時返回break移動之前所指向的位址,否則返回(void*)-1;

資源限制和rlimirt

系統為每乙個程序所分配的資源不是無限的,包括可對映的空間,因此每個程序有乙個rlimit表示當前程序可用的資源上限,這個限制可以通過getrlimit系統呼叫得到,下面**獲取當前程序虛擬記憶體空間的rlimit

其中rlimt是乙個結構體

struct rlimit

;

每種資源有硬限制和軟限制,並且可以通過setrlimit對rlimit進行有條件限制作為軟限制的上限,非特權程序只能設定軟限制,且不能超過硬限制

實現malloc

(1)資料結構

首先我們要確定所採用的資料結構。乙個簡單可行方案是將堆記憶體空間以塊的形式組織起來,每個塊由meta區和資料區組成,meta區記錄資料塊的元資訊(資料區大小、空閒標誌位、指標等等),資料區是真實分配的記憶體區域,並且資料區的第乙個位元組位址即為malloc返回的位址

可以使用如下結構體定義乙個block

typedef

struct s_block *t_block;

struck s_block;

(2)尋找合適的block

現在考慮如何在block鏈中查詢合適的block。一般來說有兩種查詢演算法:

first fit:從頭開始,使用第乙個資料區大小大於要求size的塊所謂此次分配的塊

best fit:從頭開始,遍歷所有塊,使用資料區大小大於size且差值最小的塊作為此次分配的塊

兩種方式各有千秋,best fit有較高的記憶體使用率(payload較高),而first fit具有較高的執行效率。這裡我們採用first fit演算法

t_block find_block(t_block *last,size_t size)

return b;

}

find_block從first_block開始,查詢第乙個符合要求的block並返回block起始位址,如果找不到這返回null,這裡在遍歷時會更新乙個叫last的指標,這個指標始終指向當前遍歷的block.這是為了如果找不到合適的block而開闢新block使用的。

(3)開闢新的block

如果現有block都不能滿足size的要求,則需要在鍊錶最後開闢乙個新的block。這裡關鍵是如何只使用sbrk建立乙個struct:

#define block_size 24

t_block extend_heap;

(4)**block

first fit有乙個比較致命的缺點,就是可能會讓更小的size佔據很大的一塊block,此時,為了提高payload,應該在剩餘資料區足夠大的情況下,將其**為乙個新的block

void split_block(t_block b,size_t s)

(5)malloc的實現

有了上面的**,我們就可以實現乙個簡單的malloc.注意首先我們要定義個block鍊錶的頭first_block,初始化為null;另外,我們需要剩餘空間至少有block_size+8才執行**操作

由於我們需要malloc分配的資料區是按8位元組對齊,所以size不為8的倍數時,我們需要將size調整為大於size的最小的8的倍數

size_t align8(size_t s)

#define block_size 24

void

*first_block=

null;

void

*mallloc(size_t size)

else

else

first_block = b;}}

return b->

data;

}

C語言malloc函式

malloc 標頭檔案 include 原型 void malloc size t size 引數說明 size為需要分配的記憶體空間大小,單位是byte 函式說明 在堆區分配一塊size byte大小的記憶體空間,用於存放資料,這塊記憶體空間被分配後不會被初始化,因此這些記憶體空間對應的值是未知的...

C語言之malloc函式

from msdn 百科 原型 void malloc unsigned int size include或 include malloc的全稱是memory allocation,中文叫動態記憶體 分配,當無法知道記憶體具體位置的時候,想要繫結真正的記憶體空間,就需要用到動態的分配記憶體。mall...

C語言之malloc()函式

from msdn 百科 原型 void malloc unsigned int size include或 include malloc的全稱是memory allocation,中文叫動態記憶體分配,當無法知道記憶體具體位置的時候,想要繫結真正的記憶體空間,就需要用到動態的分配記憶體。mallo...