標籤:好的 檔案 www 動態建立 緩衝 tor 時間 就是 oid
1. C語言的函數malloc和free
(1) 函數malloc和free在標頭檔<stdlib.h>中的原型及參數
void * malloc(size_t size)
動態配置記憶體,大小有size決定,傳回值成功時為任意類型指標,失敗時為NULL。
void free(void *ptr)
釋放動態申請的記憶體空間,調用free()後ptr所指向的記憶體空間被收回,如果ptr指向未知地方或者指向的空間已被收回,則會發生不可預知的錯誤,如果ptr為NULL,free不會有任何作用。
(2) C語言中典型用法
T為任意資料類型
T *p = ( T * )malloc( sizeof(T) * n)
if(NULL= =p)
{
printf(“malloc fail!\n”);
……//相關資源收回的處理
exit(-1);
}
… …//此過程不能改變指標p的指向,如果改變指標指向,那麼後面free將會出錯,因為這裡free的並不是原來的p指標,而是改變後的。當然如果改變了p的指向,那麼必須再free前,將p再指回原來的位置。這樣就沒問題了。
free(p);
p=NULL;
注意:malloc後通常要對傳回值進行判斷,避免發生不必要的錯誤。
注意,最好再p 被free掉後,加上p=NULL這句
“野指標”不是NULL指標,是指向“垃圾”記憶體(不可用記憶體)的指標。人們一般不會錯用NULL指標,因為用if語句很容易判斷。但是“野指標”是很危險的,if無法判斷一個指標是正常指標還是“野指標”。有個良好的編程習慣是避免“野指標”的唯一方法。指標p被free或者delete之後,沒有置為NULL,讓人誤以為p是個合法的指標。別看free和delete的名字(尤其是delete),它們只是把指標所指的記憶體給釋放掉,但並沒有把指標本身幹掉。此時指標指向的就是“垃圾”記憶體。釋放後的指標應立即將指標置為NULL,防止產生“野指標”。
(3) 記憶體說明
malloc函數動態申請的記憶體空間是在堆裡(而一般局部變數存於棧裡),並且該段記憶體不會被初始化,與全域變數不一樣,如果不採用手動free()加以釋放,則該段記憶體一直存在,直到程式退出才被系統,所以為了合理使用記憶體,在不適用該段記憶體時,應該調用free()。另外,如果在一個函數裡面使用過malloc,最好要配對使用free,否則容易造成記憶體泄露(沒有將記憶體還給自由儲存區)。
但是,往往會在free的時候發生段錯誤.
正確的做法是這樣:
// 在分配之前加一句判斷指標是否為空白,防止產生記憶體泄露
struct XXXX * ptr=NULL;
if (ptr == NULL) {
ptr = (struct XXXX *)malloc(num * sizeof(struct XXXX);
}
// 在釋放之前加一句判斷指標是否為空白,防止產生異常
if (ptr != NULL) {
free(ptr);
ptr = NULL;
}
補充:C 語言作為 Linux 系統上標準的程式設計語言給予了我們對動態記憶體分配很大的控制權。
然而,這種自由可能會導致嚴重的記憶體管理問題,而這些問題可能導致程式崩潰或隨時間的推移導致效能降級。
記憶體流失(即 malloc() 記憶體在對應的 free() 調用執行後永不被釋放)和緩衝區溢位(例如對以前分配到某數組的記憶體進行寫操作)是一些常見的問題,它們可能很難檢測到。這一部分將討論幾個調試工具,它們極大地簡化了檢測和找出記憶體問題的過程。
只要在代碼中添加一個標頭檔並在 gcc 語句中定義了 MEMWATCH 之後,您就可以跟蹤程式中的記憶體流失和錯誤了。MEMWATCH 支援 ANSI C,它提供結果日誌紀錄,能檢測雙重釋放(double-free)、錯誤釋放(erroneous free)、沒有釋放的記憶體(unfreed memory)、溢出和下溢等等。
這裡是memwatch的說明
補充2:轉自:http://www.cnblogs.com/yfanqiu/archive/2012/05/08/2490410.html
2. C++中的運算子new和delete
new和delete是C++中的運算子,不是庫函數,不需要庫的支援,同時,他們是封裝好的運算子。
(1)new是動態分配記憶體的運算子,自動計算需要分配的空間,在分配類類型的記憶體空間時,同時調用類的建構函式,對記憶體空間進行初始化,即完成類的初始化工作。動態分配內建類型是否自動初始化取決於變數定義的位置,在函數體外定義的變數都初始化為0,在函數體內定義的內建類型變數都不進行初始化。
(2)delete是撤銷動態申請的記憶體運算子。delete與new通常配對使用,與new的功能相反,可以對多種資料類型形式的記憶體進行撤銷,包括類,撤銷類的記憶體空間時,它要調用其解構函式,完成相應的清理工作,收回相應的記憶體資源。
(3)典型用法
int *p = new int; delete p;
char *p = new char; delete p;
類的類型 *p = new 類的類型; delete p;
//注意,指標p存於棧中,p所指向的記憶體空間卻是在堆中。
Obj * p = new Obj[100]; delete [ ]p;
//注意,new申請數組,delete刪除的形式需要加括弧“[ ]”,表示對數組空間的操作,總之,申請形式如何,釋放的形式就如何。
(4)記憶體說明。new申請的記憶體也是存於堆中,所以在不需要使用時,需要delete手動收回。
3. new/delete與malloc/free之間的聯絡和區別
(1) malloc/free和new/delete的聯絡
a)儲存方式相同。malloc和new動態申請的記憶體都位於堆中。申請的記憶體都不能自動被作業系統收回,都需要配套的free和delete來釋放。
b)除了帶有建構函式和解構函式的類等資料類型以外,對於一般資料類型,如int、char等等,兩組動態申請的方式可以通用,作用效果一樣,只是形式不一樣。
c)記憶體流失對於malloc或者new都可以檢查出來的,區別在於new可以指明是那個檔案的那一行,而malloc沒有這些資訊。
d)兩組都需要配對使用,malloc配free,new配delete,注意,這不僅僅是習慣問題,如果不配對使用,容易造成記憶體泄露。同時,在C++中,兩組之間不能混著用,雖說有時能編譯過,但容易存在較大的隱患。
(2) malloc/free和new/delete的區別
a)malloc和free返回void類型指標,new和delete直接帶具體類型的指標。
b)malloc和free屬於C語言中的函數,需要庫的支援,而new/delete是C++中的運算子,所以new/delete的執行效率高些。C++中為了兼用C文法,所以保留malloc和free的使用,但建議盡量使用new和delete。
c)在C++中, new是型別安全的,而malloc不是。例如:
int* p = new char[10]; // 編譯時間指出錯誤
delete [ ]p; //對數組需要加中括弧“[ ]”
int* p = malloc(sizeof(char )*10); // 編譯時間無法指出錯誤
free (p); //只需要所釋放記憶體的頭指標
d)使用new動態申請類對象的記憶體空間時,類對象的構建要調用建構函式,相當於對記憶體空間進行了初始化。而malloc動態申請的類對象的記憶體空間時,不會初始化,也就是說申請的記憶體空間無法使用,因為類的初始化是由建構函式完成的。delete和free的意義分別於new和malloc相反。
e)不能用malloc和free來完成類對象的動態建立和刪除。
4. C/C++程式的記憶體配置介紹
該部分參考於http://blog.csdn.net/sparkliang/archive/2008/12/30/3650324.aspx
C++的new
C++中的new其實是一個很糊弄人的術語,它有兩種不同的含義,new運算子(new operator)和new函數(operator new),值得記錄一下。
一 new運算子
最常用的是作為運算子的new,比如:
string *str = new string(“test new”);
作為運算子,new和sizeof一樣,是C++內建的,你不能對它做任何的改變,除了使用它。
new會在堆上分配一塊記憶體,並會自動調用類的建構函式。
二 new函數
第二種就是new函數,其實new運算子內部分配記憶體使用量的就是new函數,原型是:
void *operator new(size_t size);
new函數返回的是一個void指標,一塊未經初始化的記憶體。如你所見,這和C語言的malloc行為相似,你可以重載new函數,並且增加額外的參數,但是必須保證第一個參數必須是size_t類型,它指明了分配記憶體塊的大小,C++允許你這麼做,當然一般情況下這是不必要的。如果重載了new函數,在使用new操作符時調用的就是你重載後的new函數了。
如果使用new函數,和語句string *str = new string(“test new”)相對的代碼大概是如下的樣子:
string *str = (string*)operator new(sizeof(string));
str.string(“test new”); // 當然這個調用時非法的,但是編譯器是沒有這個限制的
這還不算完,還有第三種的new存在。
三 placement new
第三種,placement new,這也是new作為函數的一種用法,它允許你在一塊已存在的記憶體上分配一個對象,而記憶體上的資料不會被覆蓋或者被你主動改寫,placement new同樣由new操作符調用,調用格式是:
new (buffer) type(size_t size);
先看看下面的代碼:
char str[22];
int data = 123;
int *pa = new (&data) int;
int *pb = new (str) int(9);
結果*pa = 123(未覆蓋原資料),而*pb = 9(覆蓋原資料),可以看到placement new 並沒有分配新的記憶體,也可以使用在棧上分配的記憶體,而不限於堆。
為了使用placement new 你必須包含<new>或者<new.h>
其實placement new和第二種一樣,只不過多了參數,是函數new的重載,文法格式為:
void *operator new(size_t, void* buffer);
它看起來可能是這個樣子:
void *operator new(size_t, void* buffer) { return buffer;}
和new對應的就是delete了,需要回收記憶體啊,不然就泄漏了,這個下次再寫吧,回憶一下今天的內容先。
總結
1. 函數new
void *operator new(size_t size); 在堆上分配一塊記憶體,和placement new(void *operator new(size_t, void* buffer)); 在一塊已經存在的記憶體上建立對象,如果你已經有一塊記憶體,placement new會非常有用,事實上,它STL中有著廣泛的使用。
2. 運算子new
最常用的new,沒什麼可說的。
3. 函數new不會自動調用類的建構函式,因為它對分配的記憶體類型一無所知;而運算子new會自動調用類的建構函式。
4. 函數new允許重載,而運算子new不能被重載。
5. 緊接著就是對應的delete。
(1)棧記憶體配置運算內建於處理器的指令集中,一般使用寄存器來存取,效率很高,但是分配的記憶體容量有限。一般局部變數和函數參數的暫時存放位置。
(2)堆記憶體,亦稱動態記憶體。如malloc和new申請的記憶體空間。動態記憶體的生存期由程式員自己決定,使用非常靈活。
(3)全域代碼區:從靜態儲存地區分配。記憶體在程式編譯的時候就已經分配好,這塊記憶體在程式的整個運行期間都存在。例如全域變數,static變數。
(4)常量區:文字常量分配在文字常量區,程式結束後由系統釋放。
(5)代碼區:存放整個程式的代碼,因為儲存是資料和代碼分開儲存的。
總結:
(1)new、delete 是操作符,只能在C++中使用。malloc、free是函數,可以覆蓋,C、C++中都可以使用。(2)new 自動計算需要分配的空間大小,可以調用對象的建構函式,對應的delete調用相應的解構函式。malloc僅僅分配記憶體,free僅僅回收記憶體,並不執行構造和解構函式(3)new 型別安全、返回的是某種資料類型指標,malloc 非型別安全、返回的是void指標。
關於c語言記憶體配置,malloc,free,和段錯誤,記憶體泄露