摘要:介紹乙個動態記憶體管理模組,可以有效地檢測c程式中記憶體洩漏和寫記憶體越界等錯誤,適用於具有標準c語言
當前,絕大多數嵌入式
平台上的軟體都採用c語言編寫。除了**簡潔、執行高效之外,靈活操作記憶體的能力更是c語言的重要特色。然而,不恰當的記憶體操作通常 也是錯誤的根源之一。如「記憶體洩漏」 ——不能正確地釋放已分配的動態記憶體,就是一種非常難於檢測的存錯誤。持續的記憶體洩漏會使程式效能下降到最終完全不能執行,進而影響到所有其它有動態記憶體 需求的程式,在某些相對簡單的嵌入式
平台上甚至會妨礙作業系統的運轉。再如「寫記憶體越界」,一種不合法的寫記憶體操作,極可能破壞到本程式中正在使用的其它 資料,嚴重的時候還可能對其它正在執行的程式甚至整個系統造成影響。為此,本文介紹乙個增強的、可定製的動態記憶體管理模組(以下不妨簡稱fense),在 c語言提供的記憶體分配函式基礎上,增加了對動態記憶體的管理功能;能記錄軟體執行過程中出現的記憶體洩漏資訊,同時也具一定的監測記憶體操作的能力;可以發現絕 大多數對動態記憶體的寫越界錯誤。
1 fense的設計原理
fense通過設立乙個雙向鍊錶(struct head *sthead)來儲存所有被分配的動態記憶體塊的資訊。鍊錶中的每個節點對應乙個動態記憶體塊,節點中包括此記憶體大小、分配發生時所在的源檔名和行號以及 被釋放的時候,fense又從st_head中刪除之,檢查st_head中的節點即可得到未被釋放的本節點的數值校驗和等。fense將每乙個分配的動 態記憶體塊插入到鍊錶st_head中;當此內存放記憶體塊資訊。鍊錶節點結構定義如下:
code:
struct head;為了檢測寫越界的錯誤,fense在使用者申請的記憶體前後各增加了一定大小的記憶體作為監測區域,並初始化成預定值。這樣,當程式發生越界寫操作時,預定值就會發生改變,fense即可檢測到錯誤。/*全域性的雙向鍊錶*/
struct head *st_head=null;
通過fense分配到的動態記憶體結構如圖1所示。由此可知,fense_malloc(fense的記憶體分配函式)返回給使用者的指標ptr指向的是使用者申請記憶體區域的起始位置。鍊錶節點、前/後監測區域均為fense內部使用,是使用者不可見的。
2 使用者定製選項
fense有5組巨集定義提供給使用者對功能進行定製。各組選項控制意義如下:
warn_on_zero_malloc 使用者申請零分配空間時警告資訊。
fill_on_malloc 分配時初始化記憶體塊
fill_on_malloc_val 分配初始化時的預設值
fill_on_free 釋放時填充記憶體塊
fill_on_free_val 釋放時填充記憶體塊的預設值
以上4個選項的主要功能是初始化剛分配到的記憶體和剛被釋放的記憶體為預設值,盡可能地避免出現因使用未初始經的記憶體而引發的錯誤。
fense_front_size 定義前監測區域大小
fense_front_val 定義前監測區域的預設值
fense_end_size 定義後監測區域大小
fense_end_val 定義後監測工域的預設值
在fense工作過程中,對記憶體越界寫操作的檢驗是通過比較監測區域的當前值與本監測區域的預設值來確定的。顯然不能排除這樣一種可能:即發生在監測區域 的越界寫操作寫入的數值與監測區域的預設值恰好相同,此時,fense無法發現錯誤的發生。對於這種情況,使用者可以通過更改監測區域預設值 (fense_front_val和fense_end_val)和監測區域大小(fense_front_size和fense_end_size)為 多組不同的值來反覆測試,這樣就可以大幅度地提高監測的準確性。
validate_free
free是檢查本記憶體塊是否在鍊錶中
check_all_memory_on_free
free時檢查鍊錶中的所有記憶體塊
由於存在這樣一種情況:對記憶體塊a的寫操作出現了越界錯誤,寫到了另一記憶體塊b的區域內。此時,僅僅檢查記憶體塊a的有效性就無法發現問題,如果同時檢查所有的動態記憶體塊,則有可能發現錯誤所在。以上選項即為此而設。
fense_lock 獲取對鍊錶st_head的操作權
fense_unlock 釋放對鍊錶st_head的操作權
考慮到的在多執行緒環境中,可能有多個執行緒同時用fense進行記憶體管理,而fense使用的鍊錶st_head是全域性變數,因此提供了以上2個巨集來實現對 st_head的互斥訪問。巨集的具體定義依賴於使用者所在的軟體環境,使用者可自行實現。對於單執行緒系統,僅需將這2個巨集定義為空即可。
為便於使用,fense的標頭檔案中還包括了以下定義,使得使用者基本不用改動現有的源**就可引入fense。
code:
#define malloc(size) fense_malloc(size,_file_,_line_)3 執行時控制#define free(ptr) fense_free(ptr,_file_,_line_)
#define realloc(ptr,new_size) fense_realloc(ptr,new_size,_file_,_line_)
#define colloc(num,size) fense_calloc(num,size,_file_,_line_)
fense監測記憶體的功能可以在執行動態地開關。此功能通過將全域性變數st_disbaled賦值為零或非零來實現。在除錯過程中,可以在偵錯程式中即時修 改st_disabled的值來控制fense的行為,省去了重編譯源**的需要。對於那些需要大量編譯時間的大型工程或交叉平台開發的軟體專案來說,這 是非常有利的。
4 fense的具體實現
fense提供fense_malloc、fense_free、fense_realloc及fense_calloc等記憶體管理函式,功能和呼叫形式 與c語言中的malloc、free、realloc和calloc保持一致。限於篇幅,這裡僅對fense_malloc和fense_free的實現 過程做乙個簡單描述
code:
/*記憶體分配函式*/void *fense_malloc(size_t size,char *file,unsigned long line)
/*記憶體釋放函式*/
void fense_free(void *uptr,char *file,unsigned long line)
結束語
作為對c程式執行時的記憶體錯誤進行監測的**模組,fense能發現幾乎所有的記憶體洩漏和絕大多數的越界操作,並盡可能地記錄了改正程式錯誤所需要的資訊;有效地減少了程式設計人員的除錯時間,在實際嵌入式產品開發中取得了很好的效果。
C語言實現乙個動態記憶體的順序表
1.順序表的概念 順序表是在計算機記憶體中以 陣列 的形式儲存的線性表,是指用一組位址連續的 儲存單元 依次儲存 資料元素 的線性結構。線性表採用順序儲存的方式儲存就稱之為順序表。順序表是將表中的結點依次存放在計算機記憶體中一組位址連續的儲存單元中。2.實現函式功能 3.模組 1.seqlist.h...
c 動態記憶體的管理
我們都知道在c 中可以用new malloc動態分配記憶體空間用delete free釋放動態開闢的記憶體空間。c 中的malloc free是繼承c語言中的malloc free,它的用法和在c語言中的用法一模一樣。1.那麼既然c 中有了可以動態開闢記憶體的函式為什麼又要有new delete呢?...
C 動態記憶體管理及其與C語言動態記憶體管理的差別
在c語言中,我們常用malloc calloc realloc和free等函式來進行動態記憶體管理。但是在c 中,我們則需要用到某些操作符進行動態記憶體管理。new delete 動態管理物件 new delete 動態管理陣列 new delete 和 new delete 一定要匹配使用!否則會...