free 函式如何知道要釋放的空間大小?

時間 2021-05-13 08:34:06

1樓:黃亮anthony

其實這個乙個簡單問題,不過,大多數答案把實現和原理搞反了。

原理:不需要知道要釋放多大的空間,只需要知道哪塊空間(指標)要釋放。舉個例子,A向外借錢,每次都給乙個借條(指標),(最簡單的情況)只要記住有哪些借條就可以了,不用特別關注借條上寫了多個錢。

實現:不論你申請多大的空間,都給固定大小。(小記憶體分配的優化策略)可以在申請時記錄一下(放到乙個查詢表中)

可以多申請一點空間(在指標之前或之後)把申請了多大的空間記錄進去。

類似C++這樣的編譯期可計算型別的大小,所以可以生成類似delete(p,30),30為p指向的空間大小。補充乙個參考資料,以及示例Compiler Explorer - C++ (x86-64 gcc (trunk))

如果在記憶體池中,直接釋放池,不需要知道池中分配出去的指標對應多大的記憶體。

2樓:WangKX

malloc的分配,不是僅僅分配你申請大小的記憶體,在這個函式的內部,還額外分配出幾十個位元組用來做各種用途,包括記錄你申請的記憶體大小。

當釋放記憶體的時候,系統會到這個地方去獲取你所申請的記憶體大小,從而能夠正確知道釋放多少個位元組的記憶體;

所以,你看得出malloc()分配記憶體是造成了很多浪費的,尤其是你分配小塊記憶體【比如只有幾個位元組】,系統卻額外分配出幾十個位元組來做額外用途,這造成了很大的浪費,這就是記憶體池之所以出現的原因:記憶體池不並能提高多少效率,但是記憶體池是實實在在的能夠減少記憶體浪費的,尤其是你頻繁分配小塊記憶體時;

3樓:

在當前指標的開始記憶體區,有個資訊快,標示malloc具體大小。[資訊區|DATA|end],malloc返回DATAfree時候,DATA*-sizeof(資訊區),獲取資訊。

4樓:moji

(已經後半夜太晚了只能找找手機存貨了)

記憶體塊大概是這樣的每個記憶體塊是有header和footer的這個塊頭部標記了乙個塊的大小和是否已經使用…而malloc的時候是整塊取用的(如果有分割合併的話這個頭部資訊也會有相應的更改)

而free的時候只需要找到這個塊頭部的位址然後把這個塊有效位改為未使用就可以了

(大概的原理就是這樣子吧)

5樓:卡麥哈麥哈

我來試著說下TCMalloc的做法。

首先簡要說下結論,TCMalloc並沒有在所分配的記憶體塊中記錄其大小,而是採用了一些單獨的元資料來記錄,free()的時候可以通過查詢元資料的方式來獲取要釋放的空間的大小。而這些元資料並非是乙個記憶體塊就記錄乙個,這樣對於小額記憶體分配來說太浪費了。

下面詳細解釋一下,更詳細的解釋可以參考我的部落格TCMalloc解密,或者移步我的專欄,今天新鮮出爐的文章。

要想知道free如何得知要釋放的記憶體的大小,得先知道你要釋放的記憶體位址是如何通過malloc給到你的。看下面的圖:

TCMalloc首先將記憶體看做是乙個個8KB大小的page:

每個page都有乙個PageID,給定任意記憶體位址ptr,都可以通過將其對page大小取模的方式計算出其所在page的PageID

連續的page稱之為Span,其實就是TCMalloc定義的乙個類:

TCMalloc將256KB以內的記憶體申請(小物件)劃分為若干個類別,每個類別對應乙個大小,不管你申請多少,我都要向上取整到某一類別,然後實際分配給你的記憶體是這個類別對應的大小。每個類別對應的大小是固定不變的,記錄在乙個陣列class_to_size_中。

現在你開始呼叫malloc申請記憶體了,比如申請節,而TCMalloc發現大於節的最小的類別是第9個類別,大小為節,那就給你節。

接下來你要呼叫free釋放這塊記憶體了,假設其位址是ptr,根據上面加粗的部分,就可以找到其對應的大小了:

先計算ptr所屬page的PageID = ptr / 8KB。

再從PageMap中根據PageID查詢ptr所屬的span。

從span中得知屬於第9類別。

然後用9去索引class_to_size_陣列,得知大小節,結束。

上面是256KB以內的情況,超過256KB(中物件、大物件)的就更簡單了,直接分配給你乙個不小於你所申請大小的span,這個span是多大我當然知道。

6樓:r00tk1t

背後依賴於具體平台系統對使用者態堆的維護如果是linux的話你可以了解一下glibc的tcmalloc2的堆管理機制穿透過去實際上就是brk mmap系統呼叫反之亦然如果是windows 也差不多 libc通過HeapCreate建立了自己的堆,背後無非是HeapAlloc VirtualAlloc這些API介面介面背後是win使用者堆的管理機制

7樓:小周周的爸爸

乙個常見的實現,在malloc時候多分配乙個4位元組(不同系統大小有區別),這個多分配的空間儲存了當前分配記憶體大小。通常這個空間放在緊挨在malloc返回指標的左移位置。

8樓:Jim Liu

這個應該取決於編譯器/作業系統/基礎庫怎麼實現。

我記得當時琢磨過G++怎麼實現delete,發現是它在((size_t*)ptr)[-1]的位置隱藏分配了乙個單位來儲存ptr的長度,delete的時候就靠它了。

9樓:

這個時候就該翻原始碼啊!

glibc 的好翻 , 咱就翻它的.

翻一翻就可以發現 malloc 申請的玩意兒, 被稱作 malloc_chunk, 定義如下

struct

malloc_chunk

;雖然字段有點多, 不過至少可以看出, malloc 的時候確實申請了乙個結構體記錄了包括 size 在內的各種元資料, 而實際的返回值是 fd 欄位. 和題主的想法差不多.

至於 free 的部分就有點複雜了...

簡單來講 free 以後記憶體如果不是特別大的話, 並不被馬上歸還, 而是被管理起來, 下次 malloc 的時候如果遇到符合條件的直接扔出去, 減小系統呼叫開銷提高速度.

至於這個管理方式就有點複雜了...我自己都沒怎麼理解, 就不獻醜了.

題主願意深入了解的話可以看如下鏈結 (拉入 CTF 二進位制大坑堆概述 - CTF Wiki

堆相關資料結構 - CTF Wiki

深入理解堆的實現 - CTF Wiki

擔心被大佬學長看到, 匿了匿了.

10樓:劉生

在win32作業系統中, 使用者請求的記憶體由堆管理器分配並管理, 每一段記憶體,都會附帶乙個頭部資訊,頭部資訊中,包含該塊記憶體的大小。 其中還有一些其他資訊, 例如標誌位,表示這段記憶體是已經分配給使用者正在使用,還是處於可分分配的空閒狀態; 還包含前乙個緊挨的記憶體塊的大小,等資訊。

在win32作業系統中, 這個頭部的大小是8個位元組,正好裝在使用者指標之前。 也就是說你用malloc返回的位址,減去8就可以得到頭部的位址,裡面就包含大小資訊, 不過在window 7還是8 以後,我記不清了, 頭部被編碼了, 必須經過解碼才能讀出有效的內容。

因為有頭部的存在,當你通過free函式,把記憶體交還給堆管理器的時候,堆管理只需用傳進的位址減去8,再解碼就可以知道這個記憶體塊有多大。

11樓:三三白白

C語言的allocator實現一般都是乙個meta-data塊接malloc的記憶體位址。meta裡儲存了這段記憶體的長度,也就是meta的大小加上malloc的大小。想要知道free的大小可以自己寫乙個malloc.

h活著把記憶體分配函式包裝一層,在free的時候返回你想要的塊大小即可。

12樓:fyw

大概是這個意思。

用一種最簡單的做法舉例,每次malloc把返回指標的前一小塊用作儲存記憶體塊資訊,free時讀指標前一小塊區域,即可知道此記憶體塊大小。當然這額外的一小塊也要額外分配空間

如何理解四維空間的函式?

曼珠 首先先理清楚乙個基本概念,四維空間不同於三維空間,四維空間指的是可以擴充套件到n維的標準歐幾里得空間。即表示式ax by cz du e 0 再者,我們了解一下 維 的概念,在物理學中描述物質變化時所需的引數,這個引數就叫做維,幾個引數即幾維。N維就是兩個以上的N 1維物體垂直所形成的空間。維...

如何表示空間中的一條直線 可以使用函式的方法嗎?

BenShui 在空間內的直線,一般有三種形式可以表示 對稱式 其中 為直線上一點 為直線的方向向量.引數方程 其中 為直線上一點 為直線的方向向量.交線式 即將直線表示為兩平面相交的形式. Terrell 空間中的直線在三維建模軟體中是以引數方程的形式表達。式中 為起始點,且 是直線的方向向量。比...

我想知道我的文字水平如何,有無發展空間,如何投稿?

馬力 文字就是一種表達方式,是一種交流的方法,是一種工具,而我們要做的就是如何恰如其分的利用這一工具。我從來都沒有覺得自己是創作天才,也沒有想著能夠寫出驚天地泣鬼神的傳世佳作,但我想把自己看到的,經歷過的有意思的故事講出來,分享出來,尤其是自己生長過得那片土地,自己周圍的那些人,還有那永遠不可能再現...