1. 程式人生 > >c/c++裡的 堆區 棧區 靜態區 文字常量區 程式程式碼區

c/c++裡的 堆區 棧區 靜態區 文字常量區 程式程式碼區

一個由C/C++編譯的程式佔用的記憶體分為以下幾個部分

  1、棧區(stack)— 編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。 
       堆(heap):由malloc,new等分配的空間的地址,地址由低向高增長(程式設計師釋放)。

  2、堆區(heap) — 一般由程式設計師分配釋放, 若程式設計師不釋放,程式結束時可能由OS回收 。注意它與資料結構中的堆是兩回事,分配方式倒是類似於連結串列。 
       棧(stack):是自動分配變數,以及函式呼叫所使用的一些空間(所謂的區域性變數),地址由高向低減少;

  3、全域性區(靜態區)(static)— 全域性變數和

靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域, 未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。程式結束後由系統釋放。-->分別是data區,bbs區  

  4、文字常量區 — 常量字串就是放在這裡的,程式結束後由系統釋放 。-->coment區 

  5、程式程式碼區 — 存放函式體的二進位制程式碼。-->code區 

二、例子程式 
這是一個前輩寫的,非常詳細 
//main.cpp 
int a = 0; 全域性初始化區 
char *p1; 全域性未初始化區 
main() 

int b; 棧 
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"優化成一個地方。 

在 函式體中定義的變數通常是在棧上,用malloc, calloc, realloc等分配記憶體的函式分配得到的就是在堆上。在所有函式體外定義的是全域性量,加了static修飾符後不管在哪裡都存放在全域性區(靜態區),在 所有函式體外定義的static變量表示在該檔案中有效,不能extern到別的檔案用,在函式體內定義的static表示只在該函式體內有效。另外,函 數中的 "adgfdf "這樣的字串存放在常量區。 

還有就是函式呼叫時會在棧上有一系列的保留現場及傳遞引數的操作。棧的空間大小有限定,vc的預設是2M。棧不夠用的情況一般是程式中分配了大量陣列和遞迴函式層次太深。有一點必須知道,當一個函式呼叫完返回後它會釋放該函式中所有的棧空間。棧是由編譯器自動管理的,不用你操心。堆是動態分配記憶體的,並且你可以分配使用很大的記憶體。但是用不好會產生記憶體洩漏。並且頻繁地malloc和free會產生記憶體碎片(有點類似磁碟碎片),因為c分配動態記憶體時是尋找匹配的記憶體的。而用棧則不會產生碎片。在棧上存取資料比通過指標在堆上存取資料快些

堆(heap)和棧(stack)是C/C++程式設計不可避免會碰到的兩個基本概念。首先,這兩個概念都可以在講資料結構的書中找到,他們都是基本的資料結構,雖然棧更為簡單一些。在具體的C/C++程式設計框架中,這兩個概念並不是並行的。對底層機器程式碼的研究可以揭示,棧是機器系統提供的資料結構,而堆則是C/C++函式庫提供的。具體地說,現代計算機(序列執行機制),都直接在程式碼底層支援棧的資料結構。這體現在,有專門的暫存器指向棧所在的地址,有專門的機器指令完成資料入棧出棧的操作。這種機制的特點是效率高,支援的資料有限,一般是整數,指標,浮點數等系統直接支援的資料型別,並不直接支援其他的資料結構。因為棧的這種特點,對棧的使用在程式中是非常頻繁的。對子程式的呼叫就是直接利用棧完成的。機器的call指令裡隱含了把返回地址推入棧,然後跳轉至子程式地址的操作,而子程式中的ret指令則隱含從堆疊中彈出返回地址並跳轉之的操作。C/C++中的自動變數是直接利用棧的例子,這也就是為什麼當函式返回時,該函式的自動變數自動失效的原因。 

和棧不同,堆的資料結構並不是由系統(無論是機器系統還是作業系統)支援的,而是由函式庫提供的。基本的malloc/realloc/free函式維護了一套內部的堆資料結構。當程式使用這些函式去獲得新的記憶體空間時,這套函式首先試圖從內部堆中尋找可用的記憶體空間,如果沒有可以使用的記憶體空間,則試圖利用系統呼叫來動態增加程式資料段的記憶體大小,新分配得到的空間首先被組織進內部堆中去,然後再以適當的形式返回給呼叫者。當程式釋放分配的記憶體空間時,這片記憶體空間被返回內部堆結構中,可能會被適當的處理(比如和其他空閒空間合併成更大的空閒空間),以更適合下一次記憶體分配申請。這套複雜的分配機制實際上相當於一個記憶體分配的緩衝池(Cache),使用這套機制有如下若干原因: 
1. 系統呼叫可能不支援任意大小的記憶體分配。有些系統的系統呼叫只支援固定大小及其倍數的記憶體請求(按頁分配);這樣的話對於大量的小記憶體分類來說會造成浪費。 
2. 系統呼叫申請記憶體可能是代價昂貴的。系統呼叫可能涉及使用者態和核心態的轉換。 
3. 沒有管理的記憶體分配在大量複雜記憶體的分配釋放操作下很容易造成記憶體碎片。 

三、堆和棧的理論知識 
2.1申請 方式 
stack: 
由系統自動分配 。 例如,宣告在函式中一個區域性變數 int b; 系統自動在棧中為b開闢空間 

heap: 
需要程式設計師自己申請,並指明大小,在c中malloc函式 
如p1 = (char *)malloc(10); 
C++ 中用new運算子 
如p2 = (char *)malloc(10); 
但是注意 p1、p2本身是在棧中的。 
2.2 
申請後系統的響應 
棧:只要棧的剩餘空間大於所申請空間,系統將為程式提供記憶體 ,否則將報異常提示棧溢位。 
堆:首先應該知道作業系統有一個記錄空閒記憶體 地址的連結串列當系統 收到程式的申請時,會遍歷該連結串列,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點連結串列中刪除,並將該結點的空間分配 給程式,另外,對於大多數系統,會在這塊記憶體 空間中的首地址處記錄 本次分配 的大小,這樣,程式碼中的delete語句才能正確的釋放本記憶體 空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒連結串列 中。 
2.3申請大小的限制 
棧:在Windows下,棧是向低地址擴充套件的資料結構,是一塊連續的記憶體 的區域。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是 2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。 
堆:堆是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬記憶體 。由此可見,堆獲得的空間比較靈活,也比較大。 
2.4申請效率的比較: 
棧由系統自動分配 ,速度較快。但程式設計師是無法控制的。 
堆是由 new分配 的記憶體 ,一般速度比較慢,而且容易產生記憶體 碎片,不過用起來最方便. 
另外,在 WINDOWS下,最好的方式是用VirtualAlloc分配 記憶體 ,他不是在堆,也不是在棧是直接在程序的地址空間中保留一快記憶體 ,雖然用起來最不方便。但是速度快,也最靈活。 
2.5堆和棧中的儲存內容 
棧: 在函式呼叫時,第一個進棧的是主函式中後的下一條指令(函式呼叫語句的下一條可執行語句)的地址,然後是函式的各個引數,在大多數的C編譯器中,引數是由 右往左入棧的,然後是函式中的區域性變數。注意靜態變數是不入棧的。 
當本次函式 呼叫結束後,區域性變數先出棧,然後是引數,最後棧頂指標 指向最開始存的地址,也就是主函 數中的下一條指令,程式由該點繼續執行。 
堆:一般是在 堆的頭部用一個位元組存放堆的大小。堆中的具體內容有程式設計師安排。 
2.6存取 效率的比較 
char s1[] = "aaaaaaaaaaaaaaa"; 
char *s2 = "bbbbbbbbbbbbbbbbb"; 
aaaaaaaaaaa 是在執行時刻賦值的; 
而 bbbbbbbbbbb是在編譯時就確定的; 
但是,在以後 的存取中,在棧上的陣列 比指標 所指向的字元 串(例如堆)快。 
比如: 
#i nclude 
void main() 

char a = 1; 
char c[] = "1234567890"; 
char *p ="1234567890"; 
a = c[1]; 
a = p[1]; 
return; 

對應的彙編程式碼 
10: a = c[1]; 
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] 
0040106A 88 4D FC mov byte ptr [ebp-4],cl 
11: a = p[1]; 
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] 
00401070 8A 42 01 mov al,byte ptr [edx+1] 
00401073 88 45 FC mov byte ptr [ebp-4],al 
第一種在讀取 時直接就把字元 串中的元素讀到暫存器cl中,而第二種則要先把指標 值讀到edx中,在根據edx讀取字元 , 顯然慢了。 
2.7小結: 
堆和棧的區別可以用如下的比喻來看出: 
使用棧就象我們去飯館裡吃飯,只管點菜(發出申請)、付錢、和吃(使 用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但自由度小。 
使用堆就象是自己動手做喜歡吃的菜餚,比較麻煩,但是比較符合自己的 口味,而且自由度大。 

2.8 對比

從以上知識可知,棧是系統提供的功能,特點是快速高效,缺點是有限制,資料不靈活;而棧是函式庫提供的功能,特點是靈活方便,資料適應面廣泛,但是效率有一定降低。棧 是系統資料結構,對於程序/執行緒是唯一的;堆是函式庫內部資料結構,不一定唯一。不同堆分的記憶體無法互相操作。棧空間分靜態分配和動態分配兩種。靜態分配 是編譯器完成的,比如自動變數(auto)的分配。動態分配由alloca函式完成。棧的動態分配無需釋放(是自動),也就沒有釋放函式。為可移植的程式 起見,棧的動態分配操作是不被鼓勵的!堆空間的分配總是動態的,雖然程式結束時所有的資料空間都會被釋放回系統,但是精確的申請記憶體/釋放記憶體匹配是良好 程式的基本要素。 

操 作系統方面的堆和棧,如上面說的那些,不多說了。還有就是資料結構方面的堆和棧,這些都是不同的概念。這裡的堆實際上指的就是(滿足堆性質的)優先佇列的 一種資料結構,第1個元素有最高的優先權;棧實際上就是滿足先進後出的性質的數學或資料結構。雖然堆疊,堆疊的說法是連起來叫,但是他們還是有很大區別 的,連著叫只是由於歷史的原因。

堆和棧的生長方向恰好相反, 
|--------------| 低地址 
| 堆 | 
|--------------| 
| | | 
| I | 
| | 
| ^ | 
| 棧 | 高地址 
----------------- 
所以計算機中的堆和棧經常時放一塊講的 

一般不是必要就不要動態建立,最討厭把new出來的東西當局部變數用,用萬了馬上delete 的做法. 
理由 
1.棧分配比堆快,只需要一條指令就呢給配所有的區域性變數 
2.棧不會出現記憶體碎片 
3.棧物件好管理 

當然,某些情況下也要那麼寫,比如 
1.物件很大 
2.物件需要在某個特定的時刻構造或析夠 
3.類只允許物件動態建立,比如VCL的大多數類 
當然,必須用堆物件時也不能躲避

堆記憶體和棧記憶體各有什麼作用?堆:順序隨意   棧:先進後出


---------------------------------------------------------------------------------------------------------------------- 為什麼說在堆上分配 記憶體 比在棧上分配 記憶體 慢?堆空間的開闢需要用系統函式,棧上直接修改指標 
堆空間的管理 需 要系統記帳,棧上的空間可以由編譯器管理或是儲存在某個處理器暫存器中。 
堆空間的釋放需要系統管理,棧上的釋放可以直接丟棄。堆空間需要通過棧上的指標 間接引用,所以訪問會慢 
記得在apue2上面看到關於執行緒中有這樣一段話,大致意思是,一個 執行緒有自己的堆疊,可以在堆疊上分配 記憶體 ,比如說一個結構體,如果這個執行緒呼叫了pthread_exit()返回這個結構體指標 的時候之後要特別的小心,因為很有可能這個結構體裡面的成員值發生改變,這個可以理解,因為同一個程序所 有執行緒的資源是共享的,當這個執行緒退出之後那部分以前用過的堆疊很可能被其它執行緒佔用,但同時又說如果malloc就不會出現這樣的問題, 
比如,在棧上分一個int,只要esp-4就可以了, 
在堆上系統要記錄被分配 記憶體 的資訊,以便釋放 ---------------------------------- 
記憶體 分配 方式有三種:    

   1.從靜態儲存區域分配 。記憶體 在程式編譯的時候就已經分配 好,這塊記憶體 在程式的整個執行期間都存在。例如全域性變 量,static變數。    

   2.在棧上建立。在執行函式時,函式內區域性變數的儲存單元 都可以在棧上建立,函式執行結束時這些儲存單元 自動被 釋放。棧記憶體 分配 運算內置於處理器的指令集中,效率很 高,但是分配 的記憶體 容量有限。    

   3.從堆上分配 ,亦稱動態記憶體 分配 。程式在執行的時候用malloc或new申請任意多少的記憶體 ,程 序員自己負責在何時用free或delete釋放記憶體 。動態記憶體 的生存期由我們決定,使用非常靈活,但問題也最多。 
---------------------------------------- 
一般所說的堆疊(stack)往往是指棧,先進後出, 它是一塊記憶體 區。用以存放程式的區域性變數,臨時變數,函式的引數,返回地址等。在這塊區域中的變數的分配 和釋放由系統自動進行。不需要使用者的參與。    
   而在堆(heap,先進先出) 上的空間則是由使用者進行分配 ,並由用 戶負責釋放。 
===================================================================================

轉載地址:http://blog.chinaunix.net/uid-10221131-id-354959.html

相關推薦

C++記憶體分配方式-靜態儲存區、常量儲存區

C++中,記憶體分為5個區:堆、棧、自由儲存區、全域性/靜態儲存區和常量儲存區。棧:是由編譯器在需要時自動分配,不需要時自動清除的變數儲存區。通常存放區域性變數、函式引數等。堆:是由new分配的記憶體塊,由程式設計師釋放(編譯器不管),一般一個new與一個delete對應,一個new[]與一個del

c/c++ 靜態 文字常量 程式程式碼

一個由C/C++編譯的程式佔用的記憶體分為以下幾個部分   1、棧區(stack)— 由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。        堆(heap):由malloc,new等分配的空間的地址,地址由低向高增長(程式設計師釋放)。   2、堆區(

C/C++靜態數據詳解

編輯 bsp category 例如 錯誤 首地址 float 文件的 自己的 轉自:https://www.cnblogs.com/hanyonglu/archive/2011/04/12/2014212.html 做略微修改   本文介紹C/C++中堆,棧及

C/C++靜態資料詳解(轉載只是為了查閱方便,若侵權立刪)

C/C++堆、棧及靜態資料區詳解   本文介紹C/C++中堆,棧及靜態資料區。     五大記憶體分割槽   在C++中,記憶體分成5個區,他們分別是堆、棧、自由儲存區、全域性/靜態儲存區和常量儲存區。下面分別來介紹:   棧,就是那些由編譯器在需要的時候分配,在不需要

c語言五大記憶體分割槽-(,全域性/靜態儲存區,自由儲存區,程式碼)與可執行程式的三段-(Text段,Date段,Bss段)

一、c語言五大記憶體分割槽 棧區(stack):存放函式形參和區域性變數(auto型別),由編譯器自動分配和釋放 堆區(heap):該區由程式設計師申請後使用,需要手動釋放否則會造成記憶體洩漏。如果程式設計師沒有手動釋放,那麼程式結束時可能由OS回收。

java的靜態程式碼常量) 詳解

String s="java";和String s=new String("java");的區別這個問題困擾了我很久,搜到這篇文章,寫得炒雞棒!!! 一:在JAVA中,有六個不同的地方可以儲存資料: 1. 暫存器(register)。 這是最快的儲存區,因為它

、全域性靜態文字常量程式程式碼

一、記憶體結構圖: 二、程式碼示範區: 三:案例分析: char* 和 char[] 有什麼區別? char ch[]="abc"; 表示ch 是一個足以存放字串初值和空字元'/

全程剖析C語言中的區別

1.申請方式 (1)棧(satck):由系統自動分配。例如,宣告在函式中一個區域性變數int b;系統自動在棧中為b開闢空間。 (2)堆(heap):需程式設計師自己申請(呼叫malloc,realloc,calloc),並指明大小,並由程式設計師進行釋放。容易產生memory leak. eg:

C++new物件

http://www.jb51.net/article/40017.htm #include <iostream> using namespace std; class A { private:     int n; public:     A(int m

C語言中的區別

格式和部分內容稍作修改。 在計算機領域,堆疊是一個不容忽視的概念,我們編寫的C語言程式基本上都要用到。但對於很多的初學著來說,堆疊是一個很模糊的概念。堆疊:一種資料結構、一個在程式執行時用於存放的地方,這可能是很多初學者的認識,因為我曾經就是這麼想的和組合語言中的堆疊一

計算機中的靜態儲存區的區別

一個由C/C++編譯的程式佔用的記憶體分為以下部分:    1、棧區—由編譯器自動分配釋放,存放函式的引數值,區域性變數的值等。   2、堆區—由程式設計師分配釋放,即動態申請的區域,若程式設計師不釋放,程式結束時可能由系統回收。   3、全域性區(靜態

C語言的小坑-之方法內的常量和變數

char* fun1() {     char *a;     a = "c語言的那些小坑";     return a; } char* fun2() {     char a[128];     sprintf(a, "c語言的那些小坑");     return a;

【資料結構 C描述】使用順序編制一個滿足下列要求的程式:對於輸入的任意一個非負十進位制數,列印輸出與其等值的二進位制數。

【資料結構 C描述】使用順序棧編制一個滿足下列要求的程式:對於輸入的任意一個非負十進位制數,列印輸出與其等值的二進位制數。 //main.cpp #include <iostream> #include <malloc.h> #include <stdl

記憶體空間分配 靜態儲存區的區別

堆和棧的區別一、預備知識—程式的記憶體分配一個由c/C++編譯的程式佔用的記憶體分為以下幾個部分1、棧區(stack)— 由編譯器自動分配釋放 ,存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。2、堆區(heap) — 一般由程式設計師分配釋放, 若程式

c/c++常變數存放。靜態

學習語言,首先等知曉所敲下的程式碼做了什麼,而程式碼中最重要的就是變數與常量,這些構成函式,產生功效。 首先得清楚以下幾個知識點(或者說專有名詞) 1.生命週期:變數的作用範圍,類似生物的存活週期,對變數的使用得在其生命週期內。很好理解。 2. 記憶體:記憶體儲器的儲存

c語言—,全局文字常量,程序代碼 詳解

註意 進制 但是 ack int 運行時 內存區域 否則 數組 轉:http://www.cnblogs.com/xiaowenhui/p/4669684.html 一、預備知識—程序的內存分配 一個由C/C++編譯的程序占用的內存分為以下幾個部分1、棧區(stack)—

記憶體區劃分、記憶體分配、常量儲存區、、自由儲存區、全域性[C++][記憶體管理][轉載]

一. 在c中分為這幾個儲存區 1.棧 - 由編譯器自動分配釋放 2.堆 - 一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由OS回收 3.全域性區(靜態區),全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域,未初始化的全域性變數和未初始化的靜態變數在相鄰的另一

C/C++程式的記憶體空間及比較

C/C++程式的記憶體空間 一個由C/C++編譯的程式佔用的記憶體分為以下幾個部分: 1、棧區(stack):又編譯器自動分配釋放,存放函式的引數值,區域性變數的值等,其操作方式類似於資料結構的棧。 2、堆區(heap):一般是由程式設計師分配釋放,若程式

C++記憶體儲存區域:以及new delete

C/C++記憶體大概有: 1:棧區,它是有系統自動分配和釋放,速度快效率高,但不自由;區域性變數,函式引數,返回值等都儲存在這個區域。 2:堆區,它是由程式設計師能過new或malloc自己分配的,不過在不需要的時候也需要自己通過delete和free釋放記

、全域性靜態的理解

1、棧區: #include<stdio.h> int main(void) { int x = 2;    //在棧上面申請一個int型別長度的空間 int y[] = {1,2,3};    //在棧上面申請一個int型別