目錄
c++程式在執行時所占用的記憶體區域,一般可分為棧記憶體區、堆記憶體區、全域性/靜態記憶體區、文字常量記憶體區及程式**區5大分割槽:
下面使用日常開發中的程式設計例項,詳細介紹一下這5個分割槽,以便大家能更深刻的理解這5大記憶體分割槽。
棧記憶體區是我們用的最多的分割槽,只要有函式的地方都會使用到這個分割槽。棧分割槽是用來存放函式引數及函式區域性變數值的記憶體區,是由編譯器在編譯時自動分配和釋放的。
函式中的引數與函式中的區域性變數占用的記憶體是**執行到函式(進入函式)是分配的,在離開時函式時這些記憶體會自動被釋放。下面從下面幾個簡單的例項來更進一步地認識棧記憶體。
呼叫函式時時通過棧傳遞引數值的,即在呼叫函式之前要將函式的引數值依次壓入到棧上,然後再去call被呼叫函式的。這點從彙編**上可以清晰地看出來。比如下面一段簡單的實現兩數相加的**:
// 被呼叫函式
int addnum(int a, int b)
// 呼叫內呼叫函式的例項**
int a = 7;
int b = 8;
int nsum = addnum(a, b)程式設計客棧;
可以在vs中檢視上述c++**對應的彙編**。具體的做法是,將上述**拷貝到vs中,啟動vs除錯,在滑鼠右鍵單擊顯示的右鍵選單中點選「轉到反彙編」區檢視c++**對應的彙編**:
從上述彙編**可以看出,在呼叫addnum函式之前,將要傳入的引數a和引數b的值先壓到棧上,然後再去call addnum函式。作為被調函式的addnum會從棧上讀取傳入的引數內容。
執行緒占用的棧記憶體是有上限的,可以在建立執行緒時指定棧空間的大小。在windows上,執行緒預設的棧空間是1mb。執行緒在某一時刻的函式呼叫堆疊中的所有函式占用的棧空間總和,就是當前時刻的執行緒占用的棧記憶體。
進入函式時會將該函式的棧空間累計到所**程的棧空間占用記憶體數上(函式內部申請存放區域性變數的棧空間),離開函式則會釋放它占用的棧空間,就會將所**程占用的棧記憶體數上減掉函該函式占用的空間。如果當前執行緒占用的棧空間大於執行緒的上限時(一般是在進入乙個函式時觸發),則會報出「stack overflow」的棧溢位異常:
程式會發生崩潰。
這裡有一點需要說明一下,在某個函式中使用了switch...case語句,語句中包含了多個case分支,在這些分支中定義了一些區域性變數,雖然這些區域性變數的生命週期只位於case子句中,但是都是直接算在所在函式的棧空間上的,是剛執行進函式就分配好了,即便當前還沒執行到對應的case子句中,即便這些case子句的區域性變數的生命週期僅在case子句內!
堆記憶體也是我們最常用的記憶體區,因為每個執行緒的棧記憶體是有限的,我們一般將大部分資料要放置在堆記憶體中。
在c++中,malloc/new申請的記憶體都是從堆記憶體上分配的,用完後由free/delete區釋放的。如果沒有釋放堆記憶體,則程式結束時由作業系統統一**。
堆記憶體的管理比棧記憶體要複雜的多,如果是堆記憶體異常導致的崩潰,比棧記憶體異常(比如記憶體越界引起記憶體訪問為例)導致的崩潰,要難查的多。
如果malloc/new來的內存在用完後沒有釋放,則會導致記憶體洩露,如果頻繁執行的**中有記憶體洩露則是致命的,因為隨著程式的執行時間的加長,會產生越來越多的記憶體洩露,如果將所屬程序虛擬記憶體耗盡,會產生「out of memory」的異常:
程式直接閃退崩潰。
全域性變數和靜態變數的記憶體就是在該區上分配的,全域性變數和靜態變數的生命週期也是一樣的,都是在程式啟動時分配記憶體的,在程式退出時釋放記憶體的。
全域性變數一般會使用extern關鍵字來宣告,比如:
extern int m_nclientid;
而靜態變數則是使用static關鍵字來宣告:
s程式設計客棧tatic int ncount;
全域性變數和靜態變數都要求在定義的時候要初始化,注意此處講的定義是和宣告是相對應的概念。全域性變數和靜態變數的區別在於,全域性變數的作用域更廣,整個模組中都能使用。靜態變數則因其定義的位置不同有不同的作用域。
可以在函式中定義靜態變數,也可以在類中定義靜態成員變數。程式設計客棧函式中定義的靜態變數只能在函式中被訪問,類中定義的靜態變數則可以在類外部使用「類名::靜態成員變數名」去訪問。
該分割槽是用來存放常量值,如常量字串等,比如如下的字串常量:(將字串常量的位址賦值給指標p):
char* p = 」this is a test.」;
該字串占用的記憶體位址就是文字常量區記憶體上的。
該部分記憶體中的內容是固定的常量,是不允許修改的,程式結束後由作業系統統一**。這部分內容比較簡單,沒什麼要講的。
前面說的記憶體都是資料段的記憶體,是用來存放程式執行中的各種資料的;該部分的記憶體是**段的記憶體,是用來存放程式二進位制**的。
資料段的記憶體位址和**段指令的位址,完全是兩個概念,不能混為一談。比如某個變數的記憶體位址是資料段的位址:
某條hrsrzykkm彙編指令的位址,則是**段的位址:
是兩個完全不搭嘎的位址,一定要區分開來。
本文標題: c++程式的五大記憶體分割槽實力詳解
本文位址:
C 五大記憶體分割槽
c 五大記憶體分割槽 在c 中,記憶體分成5個區,他們分別是堆 棧 自由儲存區 全域性 靜態儲存區和常量儲存區。棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的儲存區。裡面的變數通常是區域性變數 函式引數等。堆,就是那些由new分配的記憶體塊,他們的釋放編譯器不去管,由我們的應用...
C 五大記憶體分割槽
五大記憶體分割槽 在c 中,記憶體分成5個區,他們分別是堆 棧 自由儲存區 全域性 靜態儲存區和常量儲存區。棧 就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的儲存區。裡面的變數通常是區域性變數 函式引數等。堆 就是那些由new分配的記憶體塊,他們的釋放編譯器不去管,由我們的應用程式...
五大記憶體分割槽
在c 中,記憶體分成5個區,他們分別是堆 棧 自由儲存區 全域性 靜態儲存區和常量儲存區。棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的儲存區。裡面的變數通常是區域性變數 函式引數等。堆,就是那些由new分配的記憶體塊,他們的釋放編譯器不去管,由我們的應用程式去控制,一般乙個n...