[英]A clarification regarding how free() works in C -
我的問題是有關在C中使用free()何時合適。我使用的是gcc 4.3.2。
假設,如果必須在一個鏈表中釋放一堆內存,那么理想的處理方法是(我猜):
int freeLL(node *a)
{
if(a->next != NULL)
freeLL(a->next);
free(a);
return 0;
}
現在,假設我要對以下ADT做類似的事情:
指針“ VertexNode”具有另外兩個指針:“ Vertex”和“ Edge”(例如)。 相當於說:
struct vertexnode
{
vertex *v;
edge *e;
}
typedef struct vertexnode* VertexNode;
稍后,在初始化實例時,我將執行以下操作:
VertexNode V = malloc(sizeof(struct vertexnode));
V->v = malloc(sizeof(vertex));
因此,最終在釋放時:我使用了與鏈表相同的類比。
free(V->v);
free(V);
這產生了運行時錯誤,當我注釋掉“ free(V-> v)”時,程序運行正常。 我的問題是:
a)僅僅做free(V)就足夠了嗎? 我的意思是,free()是否可以在給定指針內的所有指針上遞歸工作?
b)如果不是,在這種情況下是否存在內存泄漏? 以及我如何理想地防止這種情況發生?
c)最后,有沒有一種方法可以讓我跟蹤malloc()分配了多少字節以及free()釋放了多少字節?
很長的問題我很抱歉。 預先感謝您的時間和耐心等待。
不,免費不能遞歸工作,因此您確實會發生內存泄漏。 您正在發生的運行時錯誤可能被理解為邏輯錯誤(也許V->v
為NULL
或在釋放之前未分配它)。
如果使用linux,則使用valgrind可以幫助您分析程序並提及泄漏錯誤。 使用cc *.c -ggdb
編譯,然后運行valgrind --leakcheck=full ./a.out
將輸出泄漏錯誤。
要回答您的問題:
a)不,free()不會遞歸釋放結構的成員指針。
b)是的,在這種情況下有內存泄漏。 您必須使用代碼釋放所有分配的內存。
c)您可以使用工具輕松檢查內存泄漏,例如valgrind。 而且我知道有些項目實現了自己的內存管理,它們將malloc和free包裝在自己的API中,以便您可以跟蹤其API中的內存使用情況。
為了進行完整的內存管理,我需要一個內存池。 這將消除必須為每個被調用的malloc調用多個free的痛苦。 我使用Apache Portable Runtime(APR)進行內存池。 只需在開始初始化時分配一塊內存即可。 根據需要為每個指針分配盡可能多的內存。 然后最后只需打一個電話就可以釋放所有內存。 這比執行許多malloc和釋放會導致內存泄漏的效率要高得多。
作為旁注。 如果不使用內存池,建議您使用valgrind來測試應用程序。 實際上,您應該始終使用valgrind。
關鍵是:您需要確保要釋放的指針實際上已初始化。
我還要在調用free
之前檢查V->v
是否不為NULL
(請參閱我對您問題的評論)。
free
不是“遞歸的”。 如果您還沒有釋放e
和v
(在您的示例中),那么您正在泄漏內存。
答: free()
不能遞歸工作。 -如果您使用的是ADT概念,那么建議您通過創建createVertexNode()
函數在類型內執行分配,並在freeVertexNode()
函數內進行檢查和取消分配
B:如果您無法釋放它,那將是內存泄漏-您可以通過確保ADT函數檢查並釋放它分配的內存來避免它,或者...
C:使用內存泄漏檢查器。 Visual Studio有一個內置的,或使用其他諸如valgrind或Rational Purify。 我敢肯定,還有更多免費的開源庫,最簡單的是,它們覆蓋了malloc()和free()調用
基本上要記住的是,對malloc()
/ free()
調用應為1:1
。 如果我調用malloc()
以獲取一些內存,則需要在完成后調用free()
以將其返回。
這回答了問題a),不,它不是遞歸的。 (否則,一次調用free()
就足夠了)。
b)您打賭會有內存泄漏! 考慮一些簡單的代碼:
typedef struct pointless {
struct pointless * next;
}pl;
pl * head = malloc(sizeof(pl)); // head gets 4 bytes
pl->next = malloc(sizeof(pl)); // head->next gets 4 bytes
free(head); // head's allocated 4 bytes are deleted
顯然,這是一個毫無意義的列表,因為它僅指向下一個空元素,但它說明了這一點。 我總榜單有(4分配給它的8個字節head
,4 head
的next
)。 當我調用free()
它可以處理head
的4個字節,僅此而已。
這樣做是一件好事! 考慮從鏈接列表的中間刪除單個項目,您想釋放該節點的內存,而不是整個內存! 但是,以我上面的示例為例,您將發生內存泄漏,因為head->next
無法釋放; 一旦調用free(head)
就無法保證您可以head->next
訪問head->next
。 當然有可能...但是UB在這一點上。
c)該級別的內存管理由操作系統完成。 如果要跟蹤分配/釋放的數量,則必須執行以下操作:
int total_mem = 0;
head = malloc((total_mem += sizeof(pl)));
free(head);
total_mem -= sizeof(head);
當然,您可以在malloc()
和free()
調用周圍使用包裝器來為您做數學運算,這將更易於管理,但是您明白了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.