標籤:演算法 釋放 32位 htm 返回 計數 cout 預設 資料存放區
在c++中記憶體主要分為5個儲存區:
棧(Stack):局部變數,函數參數等儲存在該區,由編譯器自動分配和釋放.棧屬於電腦系統的資料結構,進棧出棧有相應的電腦指令支援,而且分配專門的寄存器儲存棧的地址,效率分高,記憶體空間是連續的,但棧的記憶體空間有限。
堆(Heap):需要程式員手動分配和釋放(new,delete),屬於動態分配方式。記憶體空間幾乎沒有限制,記憶體空間不連續,因此會產生記憶體片段。作業系統有一個記錄空間記憶體的鏈表,當收到記憶體申請時遍曆鏈表,找到第一個空間大於申請空間的堆節點,將該節點分配給程式,並將該節點從鏈表中刪除。一般,系統會在該記憶體空間的首地址處記錄本次分配的記憶體大小,用於delete釋放該記憶體空間。
全域/靜態儲存區:全域變數,靜態變數分配到該區,到程式結束時自動釋放,包括DATA段(全域初始化區)與BBS段(全域未初始化段)。其中,初始化的全域變數和靜態變數存放在DATA段,未初始化的全域變數和靜態變數存放在BBS段。BBS段特點:在程式執行前BBS段自動清零,所以未初始化的全域變數和靜態變數在程式執行前已經成為0.
文字常量區:存放常量,而且不允許修改。程式結束後由系統釋放。
程式碼區:存放程式的二進位代碼
使用儲存區的三種方式:
1)靜態儲存區(Static Memory)
全域變數,靜態變數及靜態類成員儲存在該區,在編譯期間就進行分配,生存期到程式結束。儲存在該區的對象只初始化一次,且在程式運行期間地址固定不變。
2)自動儲存區(Autormatic Memory)
局部變數,函數參數等儲存在該區,由編譯器自動分配和釋放
3)自由儲存區(Free Store)
由程式員手動分配和釋放記憶體(new,delete)
堆和棧的區別:
1)空間大小:棧的記憶體空間是連續的,空間大小通常是系統預先規定好的,即棧頂地址和最大空間是確定的;而堆得記憶體空間是不連續的,由一個記錄空間空間的鏈表負責管理,因此記憶體空間幾乎沒有限制,在32位系統下,記憶體空間大小可達到4G
2)管理方式:棧由編譯器自動分配和釋放,而堆需要程式員來手動分配和釋放,若忘記delete,容易產生記憶體流失。
3)生長方向不同:對於棧,他是向著記憶體位址減小的方向生長的,這也是為什麼棧的記憶體空間是有限的;而堆是向著記憶體位址增大的方向生長的
4)片段問題:由於棧的記憶體空間是連續的,先進後出的方式保證不會產生零碎的空間;而堆分配方式是每次在空閑鏈表中遍曆到第一個大於申請空間的節點,每次分配的空間大小一般不會正好等於申請的記憶體大小,頻繁的new操作勢必會產生大量的空間片段
5)分配效率:棧屬於機器系統提供的資料結構,電腦會在底層對棧提供支援,出棧進棧由專門的指令執行,因此效率較高。而堆是c/c++函數庫提供的,當申請空間時需要按照一定的演算法搜尋足夠大小的記憶體空間,當沒有足夠的空間時,還需要額外的處理,因此效率較低。
使用記憶體時幾點注意事項:
1)用new和malloc申請記憶體時,在使用前要檢查記憶體是否分配成功
char *p=new char[10];if(p==NULL)return;
2)使用記憶體之前要進行初始化
3)在對記憶體進行操作時,防止越界,如數組操作要注意下標範圍
4)對於動態分配的記憶體,一定要手動釋放,否則程式每運行一次就會丟失一部分記憶體,造成記憶體流失
5)防止記憶體釋放後繼續使用它,主要有以下三種情況:
a.程式中的對象調用關係過於複雜,實在難以搞清楚某個對象究竟是否已經釋放了記憶體,此時應該重新設計資料結構,從根本上解決對象管理的混亂局面。
b.函數的return語句寫錯了,注意不要返回指向“棧記憶體”的“指標”或者“引用”,因為該記憶體在函數體結束時被自動銷毀。
c.使用free或delete釋放了記憶體後,沒有將指標設定為NULL。導致產生“野指標”。
野指標:“野指標”不是NULL指標,是指向“垃圾”記憶體的指標。人們一般不會錯用NULL指標,因為用if語句很容易判斷。但是“野指標”是很危險的,if語句對它不起作用。
“野指標”的成因主要有三種:
(a)指標變數沒有被初始化。任何指標變數剛被建立時不會自動成為NULL指標,它的預設值是隨機的,它會亂指一氣。所以,指標變數在建立的同時應當被初始化,要麼將指標設定為NULL,要麼讓它指向合法的記憶體。
char *p; //此時p為野指標
(b)指標p被free或者delete之後,沒有置為NULL,讓人誤以為p是個合法的指標.
char *p=new char[10]; //指向堆中分配的記憶體首地址cin>> p;delete []p; //p重新變為野指標
(c)指標操作超越了變數的作用範圍。
char *p=new char[10]; //指向堆中分配的記憶體首地址cin>> p;cout<<*(p+10); //可能輸出未知資料
6)指標的注意點:
a.指標指向常量儲存區對象
char *p="abc";
此時p指向的是一個字串常量,不能對*p的內容進行寫操作,如srtcpy(p,s)是錯誤的,因為p的內容為“abc”字串常量,該資料存放區在常量儲存區,但可以對指標p進行操作,讓其指向其他的記憶體空間。
b.資源泄漏
char *p=new char[3]; //分配三個字元空間,p指向該記憶體空間
p="ab"; //此時p指向常量“ab”,而不再是new char分配的記憶體空間了,從而造成了資源泄漏
delete []p; //釋放時報錯
c.記憶體越界
char *p=new char[3]; //分配三個字元空間,p指向該記憶體空間
strcpy(p,"abcd"); //將abcd存處在分配的記憶體空間中,由於strlen("abcd")=4>3,越界
delete []p; //釋放時出錯
註:p="ab"和strcpy(p,"ab"),含義不一樣,前者指標p指向常量“ab”儲存地區的首地址,改變了p最開始指向的new申請的記憶體空間;而後者是將“ab”分配到new申請的記憶體空間中;
關於指標具體看:http://www.cnblogs.com/mrlsx/p/5419030.html
C++ 記憶體管理