2012-03-05 62 views
21

讓我們考慮這個很短的代碼片段:我可以假設調用更小尺寸的realloc會釋放餘數嗎?

#include <stdlib.h> 

int main() 
{ 
    char* a = malloc(20000); 
    char* b = realloc(a, 5); 

    free(b); 
    return 0; 
} 

閱讀手冊頁的realloc後,我不能完全肯定的是,第二條線會導致被釋放了19995個額外的字節。引用手冊頁:The realloc() function changes the size of the memory block pointed to by ptr to size bytes.,但從該定義中,我可以確定剩下的部分將被釋放嗎?

我的意思是,b指出的塊肯定包含5個空閒字節,那麼對於懶惰的compitting分配器來說,只是不會爲realloc行做任何事情?

注:我使用的分配似乎釋放19個995額外的字節,作爲註釋掉free(b)線時,所示的valgrind:

==4457== HEAP SUMMARY: 
==4457==  in use at exit: 5 bytes in 1 blocks 
==4457== total heap usage: 2 allocs, 1 frees, 20,005 bytes allocated 
+0

標準未定義標頭'':寧願使用''。同樣,從'malloc'(或'realloc')投射返回值沒有任何用處,並且可能會隱藏一個錯誤(*表示void *和int是不同的*),否則編譯器會捕獲它。 – pmg 2012-03-05 22:42:31

+1

[「由ptr參數指向的內存塊的大小更改爲字節大小,擴展或減少塊中可用的內存量。」](http://www.cplusplus.com/reference/clibrary/cstdlib/realloc /) – 2012-03-05 22:44:35

+0

@pmg ok我不知道。我將在我的代碼片段中更改 – qdii 2012-03-05 22:45:11

回答

19

是的,如果可以分配新對象,則由C標準保證。

(C99,7.20.3.4p2)「realloc函數將釋放由ptr指向的舊對象,並返回一個指向具有size指定大小的新對象的指針。

+0

[C99草案](http://people.freebsd.org/~green/c9x-draft.txt)中沒有提及任何反對realloc當舊的大小等於新的大小時什麼也不做的事情。我猜所有的實現都違反了它? – qdii 2012-03-05 23:07:25

+3

C99 7.20.3.4§4:*本realloc函數返回一個指向新的對象(其可以具有相同的值作爲一個指針,指向舊的對象)* – Christoph 2012-03-05 23:11:28

15

是—如果成功。

你的代碼片段展示了一個衆所周知的,邪惡的bug:

char* b = (char*) realloc(a, 5); 

如果成功,以前分配給a的內存將被釋放,並b將指向5個字節的內存可能或者可能不與原始塊重疊。

然而,如果調用失敗,bnull,但a仍將指向原來的內存,這將仍然有效。在這種情況下,您需要free(a)才能釋放內存。

,如果你使用普通的(危險的)成語更糟糕:

a = realloc(a, NEW_SIZE);  // Don't do this! 

如果調用realloc失敗,將null和原來的內存將被孤立,使得它無法挽回,直到你的程序退出。

+0

你說得對。我看到cppcheck抱怨這件事。我想這個是考試考試的殺手鐗,但真的,這是否曾經發生過? – qdii 2012-03-05 23:00:34

+0

@ qdii:在嵌入式世界中,所有投注都關閉;另外,操作系統可能通過'ulimit'強制實施一些限制,例如虛擬內存空間。 – Christoph 2012-03-05 23:05:38

+0

是的,這真的發生在現實世界中。爲什麼當您在內存不足的情況下(在沒有交換的系統上)出現內存不足的情況時,您會覺得這麼多糟糕的軟件崩潰而不是因爲內存不足而無法執行所請求的操作? – 2012-03-05 23:35:14

2

這取決於你的libc實現。以下所有的是符合的行爲:

  • 什麼都不做,即讓數據保持它在哪裏,並返回舊塊,用於進一步分配現在未使用的字節(據我所知這樣的再利用是可能重新使用不常見)
  • 將數據複製到一個新塊並釋放舊回OS
  • 將數據複製到一個新的塊和保留舊的進一步分配

也有可能到

  • 回報,如果一個新的塊不能被分配

在這種情況下,一個空指針,舊數據也將保持它在哪裏,這可能會導致內存泄漏,例如,如果回報值realloc()覆蓋指向該塊的唯一副本。

明智的libc實現將使用一些啓發式來確定哪種解決方案最有效。

另請注意,此說明位於實施級別:從語義上講,只要分配不失敗,realloc()就會始終釋放該對象。

+1

關於「afaik這樣的重複使用不常見」,我從來沒有聽說過現實世界的實現,原來的配置保留在原地並且沒有釋放尾部以供重用。這在病態上是不好的,雖然是合法的行爲。 – 2012-03-05 23:37:00

+0

是否有任何標準來定義這種行爲,還是它真的取決於libc的實現? – 2015-01-31 18:14:11

+1

@ rr-:C標準以及POSIX將它留給實現;我不知道任何確定行爲的規範,但它可能在libc手冊 – Christoph 2015-01-31 19:04:29

0

19995字節似乎不太可能被釋放。 更有可能的是,realloc用另一個5字節塊替換了20000字節塊,即釋放了20000字節塊並分配了新的5字節塊。

1

的realloc函數具有以下合同:

無效*結果= realloc的(PTR,new_size)

  • 如果結果爲NULL,則PTR仍然是有效的和不變。
  • 如果結果不是NULL,那麼ptr現在無效(就好像它已經被釋放了)並且不能再次使用。結果現在是指向new_size字節數據的指針。

的引擎蓋下發生的事情的確切細節是實現特定的 - 例如,結果可能是等於PTR(但超出new_size額外的空間不能再被感動)和realloc可以撥打免費的,或者可以做它自己的內部免費代表。關鍵是,作爲一名開發人員,如果realloc返回非空值,您不再對ptr負責,並且如果realloc返回NULL,您仍然對此負責。

+0

另外,傳遞new_size = 0是相同的自由(PTR )並返回NULL。這將是一種情況,其結果== NULL和ptr不再有效。 – gnasher729 2014-03-31 21:19:21

相關問題