c malloc分配記憶體

2021-07-08 13:38:20 字數 4202 閱讀 1731

php中的記憶體分配有用類似emalloc這樣的函式,emalloc實際上是c語言中的malloc的一層封裝,php啟動後,會向os申請一塊記憶體,可以理解為記憶體池,以後的php分配記憶體都是在這塊記憶體池中進行的,以至於efree,也不會向os退回記憶體,而只是設定標誌位,標識efree這塊記憶體不再使用了,這樣做的好處是,速度快,避免系統呼叫,因為頻繁的從使用者態和核心態之間的切換是很費cpu的。

c語言的malloc函式的後面是glibc(記憶體管理系統) , 前段時間在看到php記憶體分配時,看到了emalloc,又延伸看到malloc,只是知道malloc向os索要一部分記憶體,但內在的原理不知,索性google ,baidu了malloc背後的知識,腦洞大開,不禁驚嘆,自己掌握的知識太少了,雖然現在主要使用php寫東西,基本不用c,但知道一些底層的東西,也是有好處的。

一般linux預設使用的記憶體管理系統是ptmalloc

先上乙個記憶體分布的圖

1)**段

2)資料段 :定義的全域性變數和靜態變數

3)bss段:未定義的全域性變數和靜態變數

4)常量區

5)heap:堆

6)mmap:記憶體對映段

7)stack:棧

8)kenal space: 核心空間

ptmalloc管理的就是這個heap,

在寫c程式時,肯定會有乙個main函式,在執行時,main不是第乙個執行的函式,而是有另乙個函式優先於他先執行,這個時候,他會向os要一大塊記憶體,也可以理解為記憶體池,這個優先執行的函式也會進行一些分配記憶體,釋放記憶體之類的操作,我們寫c程式中關於分配記憶體的操作也是基於這個記憶體池進行的

ptmalloc把管理的記憶體分成若干大小的chunk,其結構體如下

struct

malloc_chunk;

pre_size:表示前乙個空閒的chunk的大小,如果不空閒,則該字段無意義

size:當前chunk的大小

fd,bk:只有當當前的chunk為空閒時,才有用,fd表示forward下乙個空閒chunk bk表示上乙個空閒chunk ,

當當前的chunk不為空閒時,即分配出去了,fd,bk 是沒用的,,因為該chunk已從相應bins中剔除了

fd_nextrsize,bk_nextsize:當當前chunk存放於large bins時,largs bins裡裡面的chunk是從大到小排列的,有可能存在多個相同大小的chunk,這時fd_nextsize,bk_nextsize就派上了用場,fd_nextsize表示大於當前chunk的第乙個空閒chunk,

bk_nextsize表示小於當前chunk大小的第乙個空閒chunk, 當當前chunk被分配出去時,這兩個欄位也就沒用了,因為該chunk已從相應bins中剔除了

之前看棧與堆的區別時,有的文章說malloc是在乙個被鍊錶連線起來的未使用的記憶體進行尋找的,這麼說也沒錯,只是將未使用的記憶體連線起來的不是乙個鍊錶,而是多個

ptmalloc把空閒的chunk按大小,放進4個bins(箱子中),這些箱子可以看做是 指標陣列+雙向迴圈鍊錶

unsorted bins : 緩衝區

small bins:一共63個,每一列bins子中的chunk大小都相同,但不同列的bins中的chunk大小不同,相差8位元組

large bins:稱為不定長箱子,從512位元組開始,從大到小排序

fast bins : 大概有10個bin,可以理解為快取記憶體區,基本上在64位元組以下的空閒chunk,都存放這裡,但在某種情況下,會合併,並放到unsorted bin中

__init_malloc()

1)如果要分配的記憶體大於fastbins中最大的chunk,根據待分配記憶體的大小,計算出索引值,再通過該索引找到頭指標,取出第乙個chunk, 返回給呼叫者

2)從smallbins中查詢,如果找到返回chunk

3)smallbins中找不到,則從unsorted bins中查詢,遍歷它

如果unsorted bins只有乙個chunk,並且該chunk大於待分配記憶體大小,則進行切割,餘下的chunk仍放回unsorted bins中

如果unsorted bins中的某一chunk大小 正好等於 待分配記憶體大小,則返回,並從unsorted bins中刪除

如果unsorted bins中的某一chunk大小 屬於small bins的範圍,則放入small bins的頭部

如果unsorted bins中的某一chunk大小 屬於big bins的範圍,則根據情況判斷:

根據unsorted binsk 中這個chunk 的大小,計算出所在big bins的索引值,根據此值,找到煉表頭 (放入bitmap中,表示該chunk可使用)

如unsorted bins中這個chunk 的大小 小於這個鍊錶中最小的chunk,那麼直接放到後面

如unsorted bins中這個chunk 的大小 不小於這個鍊錶中最小的chunk, 那麼就要迴圈這個鍊錶,直到找到乙個合適位置

4)從big bins中查詢,找到煉表頭後,反向遍歷此鍊錶,直到找到第乙個大小 大於待分配的chunk,然後進行切割,如果有餘下的,則放入unsorted bin中去

5)將上面的索引值加1,進行位圖法搜尋,位圖法簡單來說是,利用整形int中的每乙個位,可以表示乙個數字,這樣可節省空間,

6)如果還沒有找到,對top chunk進行分割,

7)如果存在fastbin, 則進行合併放入unsorted bins中,並回到3中

8)根據情況,如果所需記憶體位址 小於128k,使用brk在堆上進行分配,同時將top chunk收縮,如果大於128k,則使用 mmap申請記憶體

位圖法:

c語言中 int a; 在8 size大小的機器中, a佔32位,即00

0000

0000

0000

0000

0000

0000

0000

00

為了減少空間,將數字按位放到上面的**中去,例如數字8,二進位制為100000

0000

0000

0000

0000

0000

0000

0010

00

為了計算數字8在**中的位置,可將8對31求餘 ,也可以這樣:8&31=8

對於,整形陣列 int a[4] , 數字 12, 位於第0行,第12列

第0行   12/32  12>>5

第12列  a[0]|=1<

0000

0100

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

0000

00

對於ptmalloc來說,前兩行全是small bins ,後兩行全是big bins,所以在進行bit map查詢時,因為索引值已加1,所以找到的第乙個單元格如果是空閒的,則大小必定滿足條件

_int_free

1)如果free的記憶體大小 在fastbins範圍內,則直接放入相應index對應的鍊錶的第乙個chunk上,這裡使用 無鎖 實現

2)如果不在 fastbins範圍內,且不屬於mmap分配的記憶體,則看前一塊記憶體是否不再使用,如果是,則合併;再看後一塊記憶體如果不是top chunk,也進行合併,並放入unsorted bins中

如果後一塊內在是top chunk,則與top chunk合併,

如果上述合併的記憶體大小 超過64k,則將fastbins中的記憶體進行合併,一同放入unsorted bins中去

如果 top chunk的大小超過128k,則堆進行收縮,向os真正的退回記憶體

3)如果是mmap申請的記憶體,則直接向os退回記憶體

C malloc動態分配記憶體

include include intmain 靜態分配陣列 int length printf 請輸入你需要分配的陣列長度 scanf d length int parr int malloc sizeof int length malloc為分配記憶體的函式,返回第乙個位元組的位址,但是預設返回...

記憶體分配 Go記憶體管理 記憶體分配一

go作為乙個比較新晚 新 的語言,自然借鑑前輩們的優點,比如說語言本身負責記憶體管理 對協程和高併發的高優支援 簡單高效的語法等。本篇及後續的幾篇要講的就是還沒提到的比較複雜的記憶體管理。學習記憶體管理 分配 前,如果有jvm的記憶體管理的基礎,會變得非常簡單,如果是第一次接觸記憶體管理,在看完go...

C malloc函式的使用

第一次使用malloc函式,發現很好用,可以直接開闢記憶體給指標。1.在 malloc的使用.c 檔案中包含各種需要用到的標頭檔案 include 2.使用malloc語句,指定記憶體大小 int input input int malloc sizeof int 10 3.要用free函式釋放掉剛...