c程式執行記憶體檢視 對於記憶體結構的簡單理解

2021-10-13 18:13:13 字數 2905 閱讀 1101

最近花了點時間讀了《深入理解c指標》這本書,讀完這本書後,對於之前嵌入式c語言開發中很多一知半解的地方豁然開朗。對於之前學習以及工作中,很多沒有注意的問題,也有了更加深刻的理解和認識。今天就花點時間整理下這段時間讀完這本書後的所學所得,也方便後續檢視。

我們在開發c語言程式的時候,程式需要在編譯器中編譯後,才能在對應產品中執行。在程式執行的過程中,記憶體的分配一般分為以下幾個部分:

對於我們平時開發的c程式,載入到處理器的記憶體中執行,呈現出來的結構就大概分為以上五個區域。為了更好地理解,我們可以根據下面這張圖去理解。

下面我們簡單地對上述幾個區域做一下介紹。首先從**區開始。

我們需要了解的是,我們在使用c語言開發產品程式**的時候,最終的開發好的程式是並不能直接在產品的處理器中直接執行的。而是需要經過編譯器的編譯,最終將我們的**轉換成cpu處理器所能夠理解的機器指令,才能在cpu中正常執行。而**區,我們可以簡單地理解為我們編寫好的程式(已經轉換為機器指令的程式**)存放的地方。cpu處理器會從這個地方取出機器指令去完成對應的操作,最終實現我們想讓cpu所實現的功能(簡單的算術運算,或者對應的硬體操作等)。

棧區,這個區域不需要我們去維護管理,在程式執行的過程中,會自動的分配和釋放。可能有些人不太能理解這個區域是做什麼用的,這裡我們簡單地做一下介紹。

我們在開發嵌入式c程式**的過程中,經常會在定義一些函式,去完成特定的功能(例如:定義乙個addfunc函式用於實現兩個數的加法運算,或者說更加複雜的,定義乙個函式來對乙個鍊錶進行查詢操作),在這些函式中,我們不可避免地,會去定義一些區域性變數(區域性變數的概念就不在這裡做介紹了,不理解的建議去過一遍譚浩強的c語言程式開發)。在程式執行的過程中,我們需要乙個地方去儲存我們定義的這些區域性變數,呼叫函式時的引數值,返回值等,而這個地方就是棧。

棧區是處於不斷變化的狀態中,舉個例子,當前,程式執行在main函式中,此時棧中儲存的則是main函式中我們定義的一些區域性變數。這個時候,假如我們在main函式中去呼叫其他函式,那麼,棧中會自動進行出棧操作,然後再進行入棧操作,將我們呼叫的那個函式的相關的區域性變數,函式引數,返回值等都壓入到棧中。如下圖所示:

最先開始,程式從main函式開始執行,在呼叫addfunc函式之前,棧中的儲存內容可能是這樣的。

而在呼叫了addfunc函式後,棧區的內容就會被自動地替換為addfunc函式中的區域性變數等內容。在返回main函式後,又會自動進行出棧入棧操作。

我們在不斷地呼叫函式的同時,也自動不斷地進行入棧以及出棧的操作,也就是說,我們定義的區域性變數,實際上是在記憶體上不是一直會存在的,可能會在某一次的入棧及出棧操作中被覆蓋掉。舉個例子,我們可以試著編譯執行下面這段**。

這裡我們在main函式中定義了乙個區域性變數a和b,以及乙個res變數。接著我們呼叫addfunc函式,先將a和b變數的值進行相加,然後儲存到res變數中。最後輸出結果。看到這裡,如果對c語言有點基礎的朋友,就知道這種做法是得不到我們想要的預期結果的。而這就是因為我們程式在執行過程中,棧區不斷進行入棧出棧導致的。我們在main函式中定義了a,b和res後,呼叫addfunc函式,此時棧區會進行出棧以及入棧操作,在addfunc函式中,做完加法運算後,res變數的值儲存在棧中某個位址中,但是在addfunc函式返回後,會被下一次出棧入棧操作給覆蓋掉。因此我們得不到我們想要的結果。

上面介紹完棧區後,我們這裡再簡單說下堆區。其實堆區和棧區,指向的是同一片記憶體區域。不同的是,這兩個區域在這一塊記憶體區域的兩頭,隨著程式的執行,根據需要,乙個不斷向下增長,乙個不斷向上增長。(如下圖)這也是我們經常喜歡說「堆疊「,而不是將這兩個地方單獨說」棧區「或」堆區「的原因。

堆區不同於棧區的另乙個地方,就是我們程式想要在堆上開闢記憶體使用,方法不同於棧。在c程式中,我們定義了乙個區域性變數並賦值,這個過程可以理解為我們在棧上開闢了乙個空間來使用,而且我們不需要去理會這個空間後續的**問題。但是在堆上開闢空間的方法則不同。我們可以呼叫malloc函式在堆上開闢我們所需要使用的記憶體空間。在最後這段空間使用完畢後,則需要我們再呼叫free函式來釋放掉我們申請的這段空間。否則就會發生記憶體洩露問題。當記憶體洩露的次數多了,則可能出現堆疊溢位。簡單的說,就是我們一直向系統索要記憶體空間來使用,卻忘記了「歸還「,系統記憶體空間是有限的,當系統記憶體空間不夠程式執行使用時,則會導致堆疊溢位,程式再也無法正常執行。

這個區域存放的是未初始化的全域性變數和靜態變數。

這個區域存放的是已初始化的全域性變數和靜態變數,以及常量等。如下圖:

我們在main函式中,定義了a,b,c三個變數,a和b變數均儲存去資料區中,而c是乙個指標,是區域性變數,存放的是「hello world」字串的位址,而這個字串則存在於資料區。如下圖

程式執行記憶體 堆和棧

程式執行時,它的資料必須儲存在記憶體中。乙個資料項需要多大的記憶體 儲存在什麼地方 以及如何儲存都依賴與該資料項的型別。執行整的程式使用兩個記憶體區域來儲存資料 堆和棧。棧 系統接管所有的棧的操作。作為 程式設計師,不需要顯示的對它做任何事情。但了解棧的基本功能可以更好的了解程式在執行時正在做什麼。...

C程式記憶體結構

c程式記憶體結構 乙個32位的執行在保護模式下應用程式 無論是linux 還是windows 都給它分配乙個4gb的平坦的記憶體空間 乙個執行著的c程式所占用的記憶體空間分為 區 初始化資料區 未初始化資料區 堆區 和 棧區 在位址上從高位到地位為 高位 棧區堆區 未初始化資料區 即bbs 資料區 ...

C 程式記憶體結構

標籤 空格分隔 c 記憶體 棧區 stack 又編譯器自動分配釋放,存放函式的引數值,區域性變數的值等,其操作方式類似於資料結構的棧。堆區 heap 一般是由程式設計師分配釋放,若程式設計師不釋放的話,程式結束時可能由os 值得注意的是他與資料結構的堆是兩回事,分配方式倒是類似於資料結構的鍊錶。未初...