aworks編程:嵌入式c語言的內存管理
發表時間:2019-10-07 10:43:02 作者:雕刻機

很多工程師都知道,c/c++語言與其他語言不同,它需要開發者自己管理內存資源,動態內存使用不當,容易造成段錯誤或者內存泄漏,因此內存管理至關重要。本文將以c語言為例介紹動態內存管理的原理。

北京pk10开奖记录c/c++語言與其他語言不同,它需要開發者自己管理內存資源。對于動態內存的使用不當容易造成段錯誤或者內存泄漏。尤其是內存泄漏,內存泄漏往往是在程序運行一段時間才會被發現,使得開發人員無法第一時間定位錯誤。

北京pk10开奖记录而相比于個人計算機,嵌入式系統的內存資源更是稀缺。作為嵌入式c的開發人員,了解其內存管理的原理能使其更加正確地使用內存資源以及定位程序的bug。本文將以c語言為例介紹動態內存管理的原理。

動態內存的原理

1、棧空間與堆空間

北京pk10开奖记录在介紹內存管理之前,我們先解釋一下棧空間與堆空間:棧空間是由編譯器自動分配釋放,對于aworks等操作系統,在用戶創建一個任務的時候可以由自己決定任務棧空間的大小。

棧空間里面一般存放著如下數據:在函數內的局部變量(不包括static定義的變量),在調用另一個函數時保存的通用寄存器信息等。

參考如下例程(為了便于理解,省略通用寄存器等信息):

aworks編程:嵌入式c語言的內存管理

在task執行s = calculate_sum(a,b);之前,task的棧內保存如下數據:

aworks編程:嵌入式c語言的內存管理

北京pk10开奖记录程序接下來執行calculate_sum函數,其棧向下增長。在返回task之前,其棧結構如下:

aworks編程:嵌入式c語言的內存管理

執行完calculate_sum之后,根據返回地址返回task之后,棧恢復調用之前的結構:

aworks編程:嵌入式c語言的內存管理

北京pk10开奖记录所以棧空間存儲著代碼塊內的局部變量,動態地增減著內部的數據。這也就是為什么當接口調用結束后變量就不再“生存”的原因。

堆空間是由os管理的一片區域,開發者可向os動態申請一片區域用于操作數據。

北京pk10开奖记录堆空間在程序運行時一直有效,相當于定義了一個大型的全局數組。需要時向堆空間申請內存,使用完畢再還回去。這樣可以使得開發者能夠動態地控制空間的大小,而不需要在寫代碼的時候就考慮最糟的情況(定義一個數組必須在編譯之前就確定其大小,使用過程中無法增加或減少,所以必須考慮最多需要的數據大小)。

北京pk10开奖记录堆空間由編譯器決定,如果開發者想嘗試實現一片動態內存,可向堆申請一片對齊的內存空間。

北京pk10开奖记录2、內存資源的申請與釋放

北京pk10开奖记录我們這里以常用的內存操作接口——malloc與free為例,介紹操作動態內存的細節。

void* malloc(size)——申請一片大小為size字節的內存。

參考下圖,灰色部分是已經被使用的內存,空白部分則是可以被申請使用的內存。在申請內存的時候,系統會首先判斷有沒有足夠大的未被使用的區域,如果有,則將其分配給申請者,再將此區域標記為“已使用”;否則分配失敗。

aworks編程:嵌入式c語言的內存管理

北京pk10开奖记录(為方便讀圖,從這里開始我們假定內存的地址從上往下增長)

void free(void *)——釋放已申請的內存。與malloc相反,free的作用是把“已使用”的區域標記為“未使用”,那么釋放的內存下一次就可以再分配出去復用。free釋放的內存必須是malloc申請的內存。

aworks編程:嵌入式c語言的內存管理

北京pk10开奖记录由于需要對內存進行狀態標記和位置記錄(以便釋放)。在申請/釋放內存的時候需要額外的空間進行信息的記錄。有的系統會將記錄的信息集中管理,有的則是申請內存的時候額外地多申請一小片區域用于記錄。

3、內存泄漏

北京pk10开奖记录對于動態申請的內存,使用完畢之后應該還給堆,才能在后續繼續分配出去。而如果申請的內存如果沒有還回去,就造成了內存泄漏。參考如下一段代碼:

aworks編程:嵌入式c語言的內存管理

現在我們設flag=1,執行這個函數會發生什么?

aworks編程:嵌入式c語言的內存管理

北京pk10开奖记录首先ptr會指向申請的128字節的內存(圖b),然后判斷flag==1之后再申請256字節的內存(圖c)。假設我們現在使用完畢將ptr釋放:

aworks編程:嵌入式c語言的內存管理