一個由 C/C++編譯的程序占用的內存(memory)分為以下幾個部分:
1. 程序代碼區(.text) - 存放函數體的二進制代碼 。
2. 文字常量區(.rodata) - 常量字符串就是放在這裡的,程序結束後由系統釋放(rodata—read only data)。
3. 全局區/靜態區(static) - 全局變量 和 靜態變量的存儲是放在一塊的。初始化的全局變量和靜態變量在一塊區域(.rwdata or .data),未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域(.bss), 程序結束後由系統釋放。
*在 C++中,已經不再嚴格區分bss和 data了,它們共享一塊內存區域
4. 堆區(heap) - 一般由程序員分配釋放(new/malloc/calloc delete/free),若程序員不釋放,程序結束時可能由 OS 回收。
注意:它與數據結構中的堆是兩回事,但分配方式倒類似於鏈表。
5. 棧區(stack) - 由編譯器自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。
The computer program memory is organized into the following:
Code segment(text segment)
Data Segment
-- Data (rodata + rwdata)
-- BSS
-- Heap
Stack Segment
Data
The data area contains global and staticvariables used by the program that are initialized. This segment can be furtherclassified into initialized read-only (rodata) area and initialized read-writearea (rwdata).
BSS
The BSS segment also known as uninitialized datastarts at the end of the data segment and contains all uninitialized globalvariables and static variables that are initialized to zero by default.
Heap
The heap area begins at the end of the BSSsegment and grows to larger addresses from there. The heap area is managed bymalloc/calloc/realloc/new and free/delete, which may use the brk and sbrk system calls to adjust its size. The heaparea is shared by all shared libraries and dynamically loaded modules in aprocess.
Stack
The stack is a LIFO structure, typically locatedin the higher parts of memory. It usually "grows down" with everyregister, immediate value or stack frame being added to it. A stack frameconsists at minimum of a return address
例子程序
[cpp]
//main.cpp
int a = 0; // 全局初始化區(data)
char *p1; // 全局未初始化區(bss)
int main()
{
int b; // 棧區(stack)
char s[] = "abc"; // 棧區(stack)
char *p2; // 棧區(stack)
char *p3 = "123456"; // p3 在棧區(stack); "123456\0" 在常量區(rodata)
static int c =0; // 全局/靜態 初始化區 (data)
p1 = (char *)malloc(10);
p2 = (char *)malloc(20); // 分配得來的 10 和 20 字節的區域就在堆區 (heap)
strcpy(p1, "123456"); // "123456\0" 放在常量區(rodata). 編譯器可能會將它與 p3 所指向的"123456\0"優化成一個地方。
return 0;
}
堆和棧的區別
管理方式:對於棧來講,是由編譯器自動管理;對於堆來說,釋放工作由程序員控制,容易產生 memory leak。
空間大小:一般來講在 32 位系統下,堆內存可以達到接近 4G 的空間,從這個角度來看堆內存幾乎是沒有什麼限制的。但是對於棧來講,一般都是有一定的空間大小的,例如,在 VC6 下面,默認的棧空間大小大約是 1M。
碎片問題:對於堆來講,頻繁的new/delete 勢必會造成內存空間的不連續,從而造成大量碎片,使程序效率降低;對於棧來講,則不會存在這個問題,因為棧是先進後出的隊列,永遠都不可能有一個內存塊從棧中間彈出。
生長方向:對於堆來講,生長方向是向上的,也就是向著內存地址增加的方向;對於棧來講,它的生長方向是向下的,是向著內存地址減小的方向增長。
分配方式:堆都是動態分配的,沒有靜態分配的堆;棧有 2 種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部變量的分配,動態分配由 alloca 函數進行分配,但是棧的動態分配和堆是不同的,它的動態分配是由編譯器進行釋放,不需要我們手工實現。
分配效率:棧是機器系統提供的數據結構,計算機會在底層分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高; 堆則是 C/C++函數庫提供的,它的機制是很復雜的,例如為了分配一塊內存,庫函數會按照一定的算法(具體的算法可以參考數據結構/操作系統)在堆內存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由於內存碎片太多),就有可能調用系統功能去增加程序數據段的內存空間,然後進行返回。顯然,堆的效率比棧要低得多。
無論是堆還是棧,都要防止越界現象的發生。
關於 Global 和 Static 類型的一點討論
1. static 全局變量與普通的全局變量有什麼區別 ?
全局變量(外部變量)的定義之前再冠以 static 就構成了靜態的全局變量。
全局變量本身就是靜態存儲方式, 靜態全局變量當然也是靜態存儲方式。 這兩者在存儲方式上並無不同。
這兩者的區別在於非靜態全局變量的作用域是整個源程序, 當一個源程序由多個源文件組成時,非靜態的全局變量在各個源文件中都是有效的。 而靜態全局變量則限制了其作用域, 即只在定義該變量的源文件內有效, 在同一源程序的其它源文件中不能使用它。
由於靜態全局變量的作用域局限於一個源文件內,只能為該源文件內的函數公用,因此可以避免在其它源文件中引起錯誤。
static 全局變量只初使化一次,防止在其他文件單元中被引用。
2. static 局部變量和普通局部變量有什麼區別 ?
把局部變量改變為靜態變量後是改變了它的存儲方式即改變了它的生存期。把全局變量改變為靜態變量後是改變了它的作用域,限制了它的使用范圍。
static 局部變量只被初始化一次,下一次依據上一次結果值。
3. static 函數與普通函數有什麼區別?
static 函數與普通函數作用域不同,僅在本文件。只在當前源文件中使用的函數應該說明為內部函數(static),內部函數應該在當前源文件中說明和定義。對於可在當前源文件以外使用的函數,應該在一個頭文件中說明,要使用這些函數的源文件要包含這個頭文件.static 函數在內存中只有一份(.data),普通函數在每個被調用中維持一份拷貝。