C++ 棧和堆的區別和作用,以及內存分配

想要學好C++的C++堆棧,那麼就要了解什麼是C++堆棧,所爲C++堆棧就是一種數據項按序排列的數據結構,只能在一端(稱爲棧頂(top))對數據項進行插入和***,分爲堆和棧兩部分。

C++中,內存分成5個區,他們分別是堆、棧、自由存儲區、全局/靜態存儲區和常量存儲區。棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變量的存儲區。裏面的變量通常是局部變量、函數參數等。

堆,就是那些由new分配的內存塊,他們的釋放編譯器不去管,由我們的應用程序去控制,一般一個new就要對應一個delete。如果程序員沒有釋放掉,那麼在程序結束後,操作系統會自動回收。自由存儲區,就是那些由malloc等分配的內存塊,他和堆是十分相似的,不過它是用free來結束自己的生命的。

全局/靜態存儲區,全局變量和靜態變量被分配到同一塊內存中,在以前的C++堆棧中,全局變量又分爲初始化的和未初始化的,在C++裏面沒有這個區分了,他們共同佔用同一塊內存區。常量存儲區,這是一塊比較特殊的存儲區,他們裏面存放的是常量,不允許修改(當然,你要通過非正當手段也可以修改,而且方法很多)


堆棧的概念(我的理解堆就是heap,棧就是stack,有別於有些人的提法:堆棧就是指stack)對於一個C++或者任何語言的程序員都是極度重要的,除非你是隻準備停留在語言syntax層面的coder, 堆棧對於理解語言運行原理和環境實在太重要,比如你在C++中只要寫簡單一句 int arr[1000000]; 你的程序肯定就會遇到運行時的錯誤報告,其實就是stack overflow, 要知道通常stack size默認一般只有1MB(IA32 X86平臺,visual studio 2008 Express Edition),有些人就要驚訝了,那怎麼辦?用heap! 用new/delete去申請heap 裏的內存(在java中所有object都在heap裏,只有object name即object pointer是放在stack運行棧裏的),C++複雜就複雜在很多需要你自己去管理,申請動態內存,釋放動態內存,都需要自己去管理,而java相比較就簡單而且傻瓜很多了,你不用管object在哪裏,想用就直接new一個出來,也不用自己釋放,GC(Garbage Collector)會幫你釋放.

下面切入正題

一個由C/C++編譯的程序運行時佔用的內存分爲以下幾個部分
1、棧區(stack)— 程序運行時自動分配釋放 ,存放函數的參數值,局部變量的值等。其
操作方式類似於數據結構中的棧。
2、堆區(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回
收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表(僅限於C++, java有GC,方式不一樣),呵呵。
3、全局區(靜態區)(static)—,全局變量和靜態變量的存儲是放在一塊的,初始化的
全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另
一塊區域。 - 程序結束後由系統釋放。
4、文字常量區 —常量字符串就是放在這裏的。 程序結束後由系統釋放
5、程序代碼區—存放函數體的二進制代碼。


這是一個前輩寫的,非常詳細
//main.cpp
int a = 0; 全局初始化區
char *p1; 全局未初始化區
main()
{
int a; //棧
char s[] = "abc"; //棧
char *p2; //棧
char *p3 = "123456"; //123456\0在常量區,p3在棧上。
static int c =0; //全局(靜態)初始化區
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);//分配得來得10和20字節的區域就在堆區。
strcpy(p1, "123456"); //123456\0放在常量區,編譯器可能會將它與p3所指向的"123456",優化成一個地方。
}

問題1. 爲什麼說堆比棧分配慢?

棧分配空間只需要移動SP指針(bump-the-pointer technique),所以非常快,而C++堆需要在可用空間裏尋找一塊>=size的空間,通常是linked list,也就是鏈表裏查找,所以需要時間,所以說堆比棧慢。


問題2. 爲什麼說java的堆比C++快?

因爲java的GC會回收heap裏不用的object並且會壓縮compact釋放的內存片,所以之後的object佔用地址是連續的,繼續分配時只需要一個指針往後移動(bump-the-pointer technique),所以說java的堆比C++要快。



堆棧是系統使用是臨時存儲區域。它是後進先出的數據結構。
C++主要將堆棧用於函數調用。當函數調用時,各種數據被推入堆棧頂部;函數終止後的返回地址、傳遞給函數的參數、函數返回的結果以及函數中聲明的局部變量等等。因此當函數A調用函數B調用函數C,堆棧是增長了,但調用完成後,堆棧又縮小了。

是一種長期的存儲區域。程序用C++的new操作符分配堆。對new的調用 分配所需的內存並返回指向內存的指針。與堆棧不同,你必須通過調用new明確的分配堆內存。你也必須通過調用C++的delete操作符明確的釋放內存,堆不會自動釋放內存。 
如果C++中的一個類是定義在堆棧上的,就使用"."開訪問它的成員。如果是定義在堆上的,就使用"->"指針來開訪問。 但在,"->"操作符也可以用在堆棧上的類。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章