記憶體四區之程式碼區,全局區,棧區和堆區

  • 2021 年 6 月 27 日
  • 筆記

C++ 在程式執行時,將記憶體大致分為程式碼區,全局區,棧區和堆區四個區域。不同的區域存儲不同的數據,賦予不同的生命周期,能夠更靈活地進行編程。

  1. 程式碼區:存放函數體的二進位程式碼,由作業系統管理創建,程式碼區時共享的,對於頻繁被執行的程式,只需要存有一份程式碼即可;
  2. 全局區:存放全局變數和靜態變數以及常量,在程式結束後由作業系統釋放;
  3. 棧區:由編譯其自動分配釋放,存放函數的參數值以及局部變數等;
  4. 堆區:一般由程式設計師通過 new 開闢空間,進行分配和釋放,若程式設計師不釋放,則程式結束時由作業系統回收

下面通過一個例子對全局區,棧區,堆區的數據聲明周期進行說明:

// 全局變數屬於全局區,由作業系統管理釋放
int g_a = 1;
int g_b = 2;
int main(void)
{
	cout << "g_a 的地址為:\t"<< int(&g_a) << endl;
	cout << "g_b 的地址為:\t" << int(&g_b) << endl;
	// 創建普通的局部變數,屬於棧區
	int a = 10;
	int b = 20;	
	cout << "a 的地址為:\t" << int(&a) << endl;
	cout << "b 的地址為:\t" << int(&b) << endl;
	// 創建靜態變數,屬於全局區
	static int s_a = 40;
	static int s_b = 50;
	cout << "s_a 的地址為:\t" << int(&s_a) << endl;
	cout << "s_b 的地址為:\t" << int(&s_b) << endl;
	// 程式設計師自己創建變數,屬於堆區
	int* d_a = new int(10);
	int* d_b = new int(20);
	cout << "d_a 的地址為:\t" << int(d_a) << endl;
	cout << "d_b 的地址為:\t" << int(d_b) << endl;
}

輸出結果為:

g_a 的地址為:  5300224		g_b 的地址為:  5300228	
a 的地址為:    6421316		b 的地址為:    6421304
s_a 的地址為:  5300232		s_b 的地址為:  5300236
d_a 的地址為:  9547944		d_b 的地址為:  9547992

我們從中可以看到,g_ag_bs_as_b 都屬於全局區,同理,ab 都屬於棧區,d_ad_b 都屬於堆區。由於棧區的數據在程式運行結束後會被編譯器自動銷毀,因此不要返回局部變數的地址,舉例如下:

int* func()
{
	int a = 10;	// 棧區數據,在程式執行完之後自動釋放
	return &a;	//雖然返回了a的地址,然而數據在func結束時已經被銷毀
}

int main(void)
{
	int* a = func();	// 此時a表示在函數func在棧區開闢的地址,但是其中的數據已被銷毀
	cout << "a 的地址為:\t" << int(a) << "a 存放的數據為:\t" << *a << endl;
	cout << "a 的地址為:\t" << int(a) << "a 存放的數據為:\t" << *a << endl;
}

輸出結果為:

a 的地址為:    7601480a 存放的數據為: 10
a 的地址為:    7601480a 存放的數據為: 2084553696

由於編譯器會對棧區的數據做一次保留,因此第一條的 cout 語句能夠正常輸出,然而第二次的輸出才是記憶體地址 a 中的數據。

相反,堆區數據由程式設計師自己進行管理,在程式執行完之後並不會自動釋放。當整個程式執行完畢之後會由作業系統釋放。

int* func()
{
	int * a = new int(10);	// 棧區數據,在程式執行完之後自動釋放
	return a;	//雖然返回了a的地址,然而數據在func結束時已經被銷毀
}

int main(void)
{
	int* a = func();	// 此時a表示在函數func在棧區開闢的地址,但是其中的數據已被銷毀
	cout << "a 的地址為:\t" << int(a) << "a 存放的數據為:\t" << *a << endl;
	cout << "a 的地址為:\t" << int(a) << "a 存放的數據為:\t" << *a << endl;
}

輸出結果為:

a 的地址為:    23507016a 存放的數據為:        10
a 的地址為:    23507016a 存放的數據為:        10