內存分區
運行之前
我們要想執行我們編寫的c程序,那麼第一步需要對這個程序進行編譯。
|
在沒有運行程序前,也就是說程序沒有加載到內存前,可執行程序內部已經分好3段信息,分別爲代碼區(text)、數據區(data)和未初始化數據區(bss)3 個部分(有些人直接把data和bss合起來叫做靜態區或全局區)
存放 CPU 執行的機器指令。通常代碼區是可共享的(即另外的執行程序可以調用它),使其可共享的目的是對於頻繁被執行的程序,只需要在內存中有一份代碼即可。代碼區通常是隻讀的,使其只讀的原因是防止程序意外地修改了它的指令。另外,代碼區還規劃了局部變量的相關信息。
該區包含了在程序中明確被初始化的全局變量、已經初始化的靜態變量(包括全局靜態變量和局部靜態變量)和常量數據(如字符串常量)。
存入的是全局未初始化變量和未初始化靜態變量。未初始化數據區的數據在程序開始執行之前被內核初始化爲 0 或者空(NULL)。 |
總體來講說,程序源代碼被編譯之後主要分成兩種段:程序指令和程序數據。代碼段屬於程序指令,而數據域段和.bss段屬於程序數據。 |
那爲什麼把程序的指令和程序數據分開呢?
|
運行之後
程序在加載到內存前,代碼區和全局區(data和bss)的大小就是固定的,程序運行期間不能改變。然後,運行可執行程序,操作系統把物理硬盤程序load(加載)到內存,除了根據可執行程序的信息分出代碼區(text)、數據區(data)和未初始化數據區(bss)之外,還額外增加了棧區、堆區。
加載的是可執行文件代碼段,所有的可執行代碼都加載到代碼區,這塊內存是不可以在運行期間修改的。
加載的是可執行文件BSS段,位置可以分開亦可以緊靠數據段,存儲於數據段的數據(全局未初始化,靜態未初始化數據)的生存週期爲整個程序運行過程。
加載的是可執行文件數據段,存儲於數據段(全局初始化,靜態初始化數據,文字常量(只讀))的數據的生存週期爲整個程序運行過程。
棧是一種先進後出的內存結構,由編譯器自動分配釋放,存放函數的參數值、返回值、局部變量等。在程序運行過程中實時加載和釋放,因此,局部變量的生存週期爲申請到釋放該段棧空間。
堆是一個大容器,它的容量要遠遠大於棧,但沒有棧那樣先進後出的順序。用於動態內存分配。堆在內存中位於BSS區和棧區之間。一般由程序員分配和釋放,若程序員不釋放,程序結束時由操作系統回收。 |
類型 |
作用域 |
生命週期 |
存儲位置 |
auto變量 |
一對{}內 |
當前函數 |
棧區 |
static局部變量 |
一對{}內 |
整個程序運行期 |
初始化在data段,未初始化在BSS段 |
extern變量 |
整個程序 |
整個程序運行期 |
初始化在data段,未初始化在BSS段 |
static全局變量 |
當前文件 |
整個程序運行期 |
初始化在data段,未初始化在BSS段 |
extern函數 |
整個程序 |
整個程序運行期 |
代碼區 |
static函數 |
當前文件 |
整個程序運行期 |
代碼區 |
register變量 |
一對{}內 |
當前函數 |
運行時存儲在CPU寄存器 |
字符串常量 |
當前文件 |
整個程序運行期 |
data段 |
總結
在理解C/C++內存分區時,常會碰到如下術語:數據區,堆,棧,靜態區,常量區,全局區,字符串常量區,文字常量區,代碼區等等,初學者被搞得雲裏霧裏。在這裏,嘗試捋清楚以上分區的關係。
數據區包括:堆,棧,全局/靜態存儲區。
全局/靜態存儲區包括:常量區,全局區、靜態區。
常量區包括:字符串常量區、常變量區。
代碼區:存放程序編譯後的二進制代碼,不可尋址區。
可以說,C/C++內存分區其實只有兩個,即代碼區和數據區。