簡體   English   中英

關於free()在C語言中的工作方式的說明-

[英]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->vNULL或在釋放之前未分配它)。

如果使用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不是“遞歸的”。 如果您還沒有釋放ev (在您的示例中),那么您正在泄漏內存。

答: 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 headnext )。 當我調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM