在c++中內存主要分爲5個存儲區:html
棧(Stack):局部變量,函數參數等存儲在該區,由編譯器自動分配和釋放.棧屬於計算機系統的數據結構,進棧出棧有相應的計算機指令支持,並且分配專門的寄存器存儲棧的地址,效率分高,內存空間是連續的,但棧的內存空間有限。c++
堆(Heap):須要程序員手動分配和釋放(new,delete),屬於動態分配方式。內存空間幾乎沒有限制,內存空間不連續,所以會產生內存碎片。操做系統有一個記錄空間內存的鏈表,當收到內存申請時遍歷鏈表,找到第一個空間大於申請空間的堆節點,將該節點分配給程序,並將該節點從鏈表中刪除。通常,系統會在該內存空間的首地址處記錄本次分配的內存大小,用於delete釋放該內存空間。程序員
全局/靜態存儲區:全局變量,靜態變量分配到該區,到程序結束時自動釋放,包括DATA段(全局初始化區)與BBS段(全局未初始化段)。其中,初始化的全局變量和靜態變量存放在DATA段,未初始化的全局變量和靜態變量存放在BBS段。BBS段特色:在程序執行前BBS段自動清零,因此未初始化的全局變量和靜態變量在程序執行前已經成爲0.算法
文字常量區:存放常量,並且不容許修改。程序結束後由系統釋放。數組
程序代碼區:存放程序的二進制代碼數據結構
使用存儲區的三種方式:
1)靜態存儲區(Static Memory)tcp
全局變量,靜態變量及靜態類成員存儲在該區,在編譯期間就進行分配,生存期到程序結束。存儲在該區的對象只初始化一次,且在程序運行期間地址固定不變。函數
2)自動存儲區(Autormatic Memory)spa
局部變量,函數參數等存儲在該區,由編譯器自動分配和釋放操作系統
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申請的內存空間中;