Stack is used for local variables of functions and to track function calling sequences. Heap is used for allocating dynamically created variables using malloc, calloc or new.
Stack memory is freed whenever the function completes execution but the heap memory needs to be freed explicitly using delete, free or by garbage collector of the language.
Stack memory of a process is fixed size and heap is variable memory.
Stack is faster than heap as allocating memory on stack is simpler just moving stack pointer up.
In case of multi threading, each thread of process will have a different stack but all threads share single heap
一、預備知識—程序的內存分配
一個由c/C++編譯的程序佔用的內存分為以下幾個部分
1、Stack區(stack)— 由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的Stack。
2、Heap區(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的Heap是兩回事,分配方式倒是類似於鏈表,呵呵。
3、全局區(靜態區)(static)—,全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。 - 程序結束後有系統釋放
4、文字常量區 —常量字符串就是放在這裡的。 程序結束後由系統釋放
5、程序代碼區—存放函數體的二進制代碼。
二、例子程序
這是一個前輩寫的,非常詳細
//main.cpp
int a = 0; 全局初始化區
char *p1; 全局未初始化區
main()
{
int b; Stack
char s[] = "abc"; Stack
char *p2; Stack
char *p3 = "123456"; 123456\0在常量區,p3在Stack上。
static int c =0; 全局(靜態)初始化區
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得來得10和20字節的區域就在Heap區。
strcpy(p1, "123456"); 123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。
}
二、Heap和Stack的理論知識
2.1申請方式
stack:
由系統自動分配。 例如,聲明在函數中一個局部變量 int b; 系統自動在Stack中為b開闢空間
heap:
需要程序員自己申請,並指明大小,在c中malloc函數
如p1 = (char *)malloc(10);
在C++中用new運算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在Stack中的。
2.2
申請後系統的響應
Stack:只要Stack的剩餘空間大於所申請空間,系統將為程序提供內存,否則將報異常提示Stack溢出。
Heap:首先應該知道操作系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時,
會遍歷該鏈表,尋找第一個空間大於所申請空間的Heap結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊 內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。另外,由於找到的Heap結點的大小不一定正好等於申請的 大小,系統會自動的將多餘的那部分重新放入空閒鏈表中。
2.3申請大小的限制
Stack:在Windows下,Stack是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是Stack頂的地址和Stack的最大容量是系統預先規定好的,在 WINDOWS下,Stack的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過Stack的剩餘空間時,將提示overflow。因 此,能從Stack獲得的空間較小。
Heap:Heap是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。Heap的大小受限於計算機系統中有效的虛擬內存。由此可見,Heap獲得的空間比較靈活,也比較大。
2.4申請效率的比較:
Stack由系統自動分配,速度較快。但程序員是無法控制的。
Heap是由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,他不是在Heap,也不是在Stack是直接在進程的地址空間中保留一快內存,雖然用起來最不方便。但是速度快,也最靈活
2.5Heap和Stack中的存儲內容
Stack: 在函數調用時,第一個進Stack的是主函數中後的下一條指令(函數調用語句的下一條可執行語句)的地址,然後是函數的各個參數,在大多數的C編譯器中,參數是由右往左入Stack的,然後是函數中的局部變量。注意靜態變量是不入Stack的。
當本次函數調用結束後,局部變量先出Stack,然後是參數,最後Stack頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。
Heap:一般是在Heap的頭部用一個字節存放Heap的大小。Heap中的具體內容有程序員安排。
2.6存取效率的比較
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在運行時刻賦值的;
而bbbbbbbbbbb是在編譯時就確定的;
但是,在以後的存取中,在Stack上的數組比指針所指向的字符串(例如Heap)快。
比如:
#include;
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小結:
Heap和Stack的區別可以用如下的比喻來看出:
使用Stack就像我們去飯館裡吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。
使用Heap就像是自己動手做喜歡吃的菜餚,比較麻煩,但是比較符合自己的口味,而且自由度大。
Heap和Stack的區別主要分:
操作系統方面的Heap和Stack,如上面說的那些,不多說了。
還有就是數據結構方面的Heap和Stack,這些都是不同的概念。這裡的Heap實際上指的就是(滿足Heap性質的)優先隊列的一種數據結構,第1個元素有最高的優先權;Stack實際上就是滿足先進後出的性質的數學或數據結構。
雖然HeapStack,HeapStack的說法是連起來叫,但是他們還是有很大區別的,連著叫只是由於歷史的原因。
一個由c/C++編譯的程序佔用的內存分為以下幾個部分
1、Stack區(stack)— 由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的Stack。
2、Heap區(heap) — 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的Heap是兩回事,分配方式倒是類似於鏈表,呵呵。
3、全局區(靜態區)(static)—,全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域。 - 程序結束後有系統釋放
4、文字常量區 —常量字符串就是放在這裡的。 程序結束後由系統釋放
5、程序代碼區—存放函數體的二進制代碼。
二、例子程序
這是一個前輩寫的,非常詳細
//main.cpp
int a = 0; 全局初始化區
char *p1; 全局未初始化區
main()
{
int b; Stack
char s[] = "abc"; Stack
char *p2; Stack
char *p3 = "123456"; 123456\0在常量區,p3在Stack上。
static int c =0; 全局(靜態)初始化區
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得來得10和20字節的區域就在Heap區。
strcpy(p1, "123456"); 123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。
}
二、Heap和Stack的理論知識
2.1申請方式
stack:
由系統自動分配。 例如,聲明在函數中一個局部變量 int b; 系統自動在Stack中為b開闢空間
heap:
需要程序員自己申請,並指明大小,在c中malloc函數
如p1 = (char *)malloc(10);
在C++中用new運算符
如p2 = (char *)malloc(10);
但是注意p1、p2本身是在Stack中的。
2.2
申請後系統的響應
Stack:只要Stack的剩餘空間大於所申請空間,系統將為程序提供內存,否則將報異常提示Stack溢出。
Heap:首先應該知道操作系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時,
會遍歷該鏈表,尋找第一個空間大於所申請空間的Heap結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊 內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。另外,由於找到的Heap結點的大小不一定正好等於申請的 大小,系統會自動的將多餘的那部分重新放入空閒鏈表中。
2.3申請大小的限制
Stack:在Windows下,Stack是向低地址擴展的數據結構,是一塊連續的內存的區域。這句話的意思是Stack頂的地址和Stack的最大容量是系統預先規定好的,在 WINDOWS下,Stack的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過Stack的剩餘空間時,將提示overflow。因 此,能從Stack獲得的空間較小。
Heap:Heap是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。Heap的大小受限於計算機系統中有效的虛擬內存。由此可見,Heap獲得的空間比較靈活,也比較大。
2.4申請效率的比較:
Stack由系統自動分配,速度較快。但程序員是無法控制的。
Heap是由new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便.
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內存,他不是在Heap,也不是在Stack是直接在進程的地址空間中保留一快內存,雖然用起來最不方便。但是速度快,也最靈活
2.5Heap和Stack中的存儲內容
Stack: 在函數調用時,第一個進Stack的是主函數中後的下一條指令(函數調用語句的下一條可執行語句)的地址,然後是函數的各個參數,在大多數的C編譯器中,參數是由右往左入Stack的,然後是函數中的局部變量。注意靜態變量是不入Stack的。
當本次函數調用結束後,局部變量先出Stack,然後是參數,最後Stack頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。
Heap:一般是在Heap的頭部用一個字節存放Heap的大小。Heap中的具體內容有程序員安排。
2.6存取效率的比較
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在運行時刻賦值的;
而bbbbbbbbbbb是在編譯時就確定的;
但是,在以後的存取中,在Stack上的數組比指針所指向的字符串(例如Heap)快。
比如:
#include
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小結:
Heap和Stack的區別可以用如下的比喻來看出:
使用Stack就像我們去飯館裡吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。
使用Heap就像是自己動手做喜歡吃的菜餚,比較麻煩,但是比較符合自己的口味,而且自由度大。
Heap和Stack的區別主要分:
操作系統方面的Heap和Stack,如上面說的那些,不多說了。
還有就是數據結構方面的Heap和Stack,這些都是不同的概念。這裡的Heap實際上指的就是(滿足Heap性質的)優先隊列的一種數據結構,第1個元素有最高的優先權;Stack實際上就是滿足先進後出的性質的數學或數據結構。
雖然HeapStack,HeapStack的說法是連起來叫,但是他們還是有很大區別的,連著叫只是由於歷史的原因。
沒有留言:
張貼留言