如有錯誤,希望留言指正。
理解局部變數和全局變數的記憶體問題核心是理解編譯器在主函數和子函數調用執行過程中是如何管理分配記憶體的。
記憶體中數據區被分為動態數據區與靜態數據區。其中靜態數據區可以簡單理解為寫在main函數與其他函數外部的全局變數存儲的區域,程式運行時,編譯器為其在這個區域內分配記憶體,其生命周期貫穿整個程式執行過程。
這裡我們主要講講動態數據區,動態數據區中主要分為heap與stack。假設下圖為記憶體區域,其中的堆區和棧區分別具有基地址;堆區和棧區的記憶體分配都是先從基地址開始分配,併在記憶體釋放後指針再次回到基地址。這裡紅色邊框區域為堆區,藍色為棧區;其中主函數中的變數在堆區分配,而主函數中調用的函數內部的局部變數在棧區分配,其生命周期為整個子函數調用期。以下麵最簡單的小程式的執行為例:
堆基地址 |
(棧基地址) |
void f(int c) { int e; int f; } int main() { int a=1; int b=2; f(a);
int d=3;
f(b); return 0; }
首先程式從主函數開始執行,執行語句int a;int b;此時編譯器在堆區依次為其分配記憶體。
b=2 |
堆基 a=1 |
f |
e |
棧基 c |
當第一次調用子函數f時, c,e,f依次進棧(圖中省略了棧頂指針);
當第一次子函數f調用後,棧區記憶體被釋放,相當於f,e,c依次出棧,棧頂指針回到基地址,而此時,堆區記憶體並未釋放,因為主函數還沒有結束。int d=3;執行之後:
d=3 |
b=2 |
堆基 a=1 |
棧基 |
此時棧區為空,當再次執行子函數f時,如同第一次一樣,編譯器再次在棧區為其變數分配記憶體,從而局部變數進棧。f調用結束,棧區記憶體釋放。在遞歸演算法的執行過程中,函數不斷調用自身,編譯器為每個子函數開闢棧區空間,其實現類似於此。當主函數結束後,堆區的記憶體才被釋放。
大多數時候,編譯器在編譯時在記憶體中做了很多工作,我們不能從代碼本身瞭解記憶體分配,例如理解 i++ 語句與i=i+1的區別,乍一看一樣,無非是給i 加1,但記憶體中卻有本質的區別,i=i+1 執行過程中,編譯器首先會將i+1的值保存在一個臨時變數中,這個臨時變數編譯器自動申請,然後再把這個臨時變數賦值給i , 而i++則直接給i加1;
更多c與c++記憶體分配問題請參考 http://www.cnblogs.com/dolphin0520/archive/2011/04/04/2005061.html