精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Keil C的應用動態存儲管理的原理和實現方法分析

牽手一起夢 ? 來源:單片機與嵌入式系統應用 ? 作者:丁明亮,熊真春 ? 2020-10-04 14:00 ? 次閱讀

Keil C是常用的嵌入式系統編程工具,它通過init_mempool、mallloe、free等函數,提供了動態存儲管理等功能。本文通過對init_mempool、mallloe和free這3個KeilC庫函數源代碼的分析,揭示其實現的原理和方法,并對其中的不足作了改進,以使Keil C編程人員更好地應用動態存儲管理。

1 相關數據結構、變量及說明

在Keil C安裝目錄下的\c5l\lib目錄下,有實現init_mempool、mallloe和free這3個函數的C源文件init_mere.c、malloc.e和free.c。下面針對keil C7.5A版,將其中與動態存儲管理相關的數據結構介紹如下:

Keil C的應用動態存儲管理的原理和實現方法分析

該結構的next指向堆中的下一空閑內存塊,len表示該空閑塊除去該塊首部的struct__mem__結構所占的字節數后,該塊實際可用的字節數。由于next是一個指向XDATA區的指針,故在Keil C中應用程序所定義的堆空間應在XDATA段中定義。

在Keil C中,堆中的所有空閑內存塊是用一個單鏈表來管理的,struct_mere_即為該鏈表結點的結構,后面定義的宏AVAIL為該鏈表的首結點,為敘述方便,以下將該鏈表稱為AVAIL鏈表。

#define AVAIL(__meM_avaiL_[O])

全局數組__meM_ avail_實際也是struct__mem__類型,__mem_avail__[O]的next指向堆中首塊空閑塊。如果堆中已無空閑內存塊,則__mem_avail__[0]的next為NULL(0值)。為使程序代碼簡潔,定義了宏AVAIL來代替__mem_avail__[O]。

2 init_mempool函數剖析

函數int_mempool(void_MALLOC_MEM_*pool,unsigned int size)失敗時將返回0,成功則返回一1,參數pool指向應用程序定義的堆空間,參數size為堆空間的字節數。如果應用程序提供的堆空間太小(size的值太小),將失去實際意義,故函數將返回0表示失敗。當size參數足夠大,則會初始化AVAIL(即_mem_avail__[O]),使其next域指向pool參數所指向的堆空間,len域為pool參數所指向的堆空間的總字節數size。其在KeilC 7.5A庫中init_mem.C的源代碼如下:

在成功執行init_mempool函數后,將得到如圖1所示的一個數據結構。另外,鏈首結點AVAIL的len域記錄了整個堆的字節數。鏈首AVAIL結點的next域指向的是首塊空閑塊,當經過多次的malloe函數而堆中投有空閑內存塊時,AVAIL結點的next域將為NULL值。

很明顯,從上面的if(pool==NULL){pool=1;size--;)這部分源代碼來看,如果應用程序中pool參數為空指針(pool為0)時,顯然不能直接將AVAIL,的next域的值賦為空指針的(即賦為O)。將pool的值改為1,再將size的值減l,這樣,init_mempool函數會在XDATA區中,從地址l開始,取size一1個字節作為堆來使用。如果源程序有定義在XDATA區的變量,則這些變量所占的存儲單元也可能會被當成堆空間的一部分,這無疑是有潛在風險的。

部分程序員在調用init_mempool函數時,習慣將pool參數設為一個形如0xAAAA數字表示的絕對地址,如果不加特別防范,也是不妥的,因為Keil C可能會在此方式指定的堆空間中分配臨時變量。好的習慣是定義一個字節數組作為堆空間,再將數組名作為pool參數調用init_mempool函數。

在Keil C的聯機文檔中,指明了init_mempool在應用程序中只能被調用一次,那么,如果多次調用該函數又會有什么后果呢?從該函數的源代碼來分析,多次調用init_mempoo1函數,會導致重新初始化首結點AVAIL的next域和len域的值,將使AVAIL鏈表中的原有管理信息丟失,從而導致一些很難診斷的問題。

對此問題,可采用如下保護措施。當發現AVAIL鏈表中已有管理信息時,則返回失敗標志,函數直接返回。具體的方法是檢查AVAIL結點的len域,由于其被初始化為零,如果發現其值非零,則表明init_mempool函數已被成功調用過,此時函數直接返回。

3 malloc函數分析

malloc函數的原形是void *malloc(unsigned intsize),size參數為需動態申請的內存塊的字節數。

malloc函數的算法是查找AVAIL鏈表中各結點next指針所指向的空閑內存塊。如果某塊的空閑字節數≥size參數,則停止查找,并從該塊進行內存分配,返回一個指向所分配內存塊的指針給應用程序。如果沒有找到符合要求的空閑內存塊,則返回空指針給應用程序。

需要注意的是,AVAIL鏈表中除首結點AVAIL外,其余各節點位于堆中各空閑內存塊開始處的一個struct__mem__結構中,其len域為該空閑塊總字節數減去sizeof(stiuct__mem)后的值,即該塊實際空閑的字節數;next域指向堆中下一空閑內存塊。

設鏈表節點p指向所找到的空閑內存塊,如果在p空閑塊分配size個字節后,剩余的字節數不多,則將p塊從AVAIL鏈表中刪除,然后返回一個指向p塊偏移sizeof(struct__mem)處的指針。如果在p空閑塊分配size個字節后,該塊仍剩余較多的字節數,則需對該塊進行分割,將多出的這一部分保留在AVAIL鏈表中。(以下部分有省略,全文請見本刊網站——編者注)

4 free函數分析及改進

free函數的原形是void free(void xdata *memp),參數memp指向所要釋放的內存塊。

在AVAIL鏈表中,各結點是按其所指空閑內存塊開始地址的大小按升序排列的。free函數的算法是在AVAIL鏈表中查一個節點p(其前驅為q),當p節點所指空問內存塊的地址大于參數memp所指內存塊的起始地址時,則將memp塊插入到該節點之前,如沒有找到這樣的節點,則memp塊插到鏈尾。在插入memp塊時,還將檢查在memp塊的前后是否存在地址相鄰的空閑內存塊,如果有,則將memp塊與相鄰塊合并。

值得探討的是最后一段將memp塊與前一塊(q塊)合并的這部分代碼。如果在執行此部分代碼之前,q指向首結點AVAIL,而此時欲將q塊與memp塊合并,顯然是不合理的。實際上,此時應當將q的next指針的值設為memp塊的開始地址p0。由于KeilC7.5A中,free庫函數的源程序中沒有考慮這種特殊情況,因此可能會引發嚴重后果。

由源代碼分析可知,q指向首結點AVAIL,而此時如果滿足。memp塊與q塊合并的判定條件,執行q>1en+=p0一>Len+HL,EN和q一>next=pO一>next后,不但不能回收內存,反而導致memp塊丟失;同時,AVAIL的len域的值也不正確。如果此時pO一>next又為NULL,則會導致整個堆內存的丟失。

筆者特在Keil C7.5 A版中設計了一個示例(見本刊網站),用于引發該錯誤。要防止這種錯誤,只需將if((((char_MALLOC_MEM_*)q)+q一>len+HLEN)==pO)判定語句改為if((q!=&AVAIL)&&(((char_MALLOC_MEM_*)q)+q一>len+HLEN)==p0)即可。有興趣的可通過電子郵件與筆者聯系(cqdoml@sina.com)。

責任編輯:gt

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5068

    文章

    19021

    瀏覽量

    303319
  • 編程
    +關注

    關注

    88

    文章

    3594

    瀏覽量

    93600
  • 函數
    +關注

    關注

    3

    文章

    4307

    瀏覽量

    62432
收藏 人收藏

    評論

    相關推薦

    Keil C動態內存管理機制分析及改進,不看肯定后悔

    Keil C動態內存管理機制分析及改進,不看肯定后悔
    發表于 04-25 08:48

    有什么方法可以實現邏輯分析儀的實時存儲嗎?

    有什么方法可以實現邏輯分析儀的實時存儲嗎?
    發表于 05-06 07:39

    怎樣去實現嵌入式裸機內存動態管理

    嵌入式裸機內存動態管理實現與講解(一)C 的標準庫自帶了malloc和free,為啥還要自己實現?標準庫的函數占用空間較大,采用本文的
    發表于 12-17 07:02

    基于對象存儲中的元數據組織管理方法

    提出了一種動態分區元數據組織管理方法它混合了動態和靜態的方法在MDS 機群中分布元數據并使用散列的技術索引元數據利用共享存儲來存放元數據整個
    發表于 06-28 17:03 ?53次下載
    基于對象<b class='flag-5'>存儲</b>中的元數據組織<b class='flag-5'>管理方法</b>

    XXTEA加密算法的KEIL C實現

    本內容提供了XXTEA加密算法的KEIL C實現,詳細列出了程序共大家學習
    發表于 08-25 17:57 ?3304次閱讀

    keil C51 uVision2安裝方法

    keil C51 uVision2安裝方法
    發表于 11-03 10:27 ?7次下載

    Keil-C51與MDK-ARM并存方法

    Keil-C51與MDK-ARM并存方法
    發表于 03-14 17:45 ?21次下載

    基于C/S醫療設備全過程動態管理信息系統

    設計一套醫療設備的全過程動態管理信息系統。方法分析系統的整體框架,將系統分成購置管理、資產管理
    發表于 12-05 10:57 ?0次下載
    基于<b class='flag-5'>C</b>/S醫療設備全過程<b class='flag-5'>動態</b><b class='flag-5'>管理</b>信息系統

    基于對象跟蹤的動態分析方法

    Web程序的安全威脅主要是由外部輸入未驗證引發的安全漏洞,如數據庫注入漏洞和跨站腳本漏洞,動態污點分析可有效定位此類漏洞。提出一種基于對象跟蹤的動態分析
    發表于 01-05 16:21 ?0次下載
    基于對象跟蹤的<b class='flag-5'>動態</b><b class='flag-5'>分析</b><b class='flag-5'>方法</b>

    Keil C51單片機變量的使用方法詳細介紹

    8051內核單片機是一種通用單片機,在國內占有較大的市場份額。在將C語言用于51內核單片機的研究方面,Keil公司做得最為成功。由于51內核單片機的存儲結構的特殊性,Keil
    發表于 11-24 10:20 ?4636次閱讀
    <b class='flag-5'>Keil</b> <b class='flag-5'>C</b>51單片機變量的使用<b class='flag-5'>方法</b>詳細介紹

    keil C51應用程序和安裝方法

    keil C51應用程序和安裝方法
    發表于 11-27 08:00 ?11次下載

    如何在KEIL C實現直接尋址和間接尋址

    本文檔的主要內容詳細介紹的是如何在KEIL C實現直接尋址和間接尋址。
    發表于 07-02 17:42 ?0次下載
    如何在<b class='flag-5'>KEIL</b> <b class='flag-5'>C</b>中<b class='flag-5'>實現</b>直接尋址和間接尋址

    怎么樣才能使用Keil C51開發大型嵌入式程序

     結合在8051系列單片機平臺上的實際開發應用的經驗,介紹用 Keil C在8051單片機上進行大型嵌入式程序開發的技術。主要闡述了大型嵌入式開發中在存儲器的管理
    發表于 07-01 08:00 ?12次下載
    怎么樣才能使用<b class='flag-5'>Keil</b> <b class='flag-5'>C</b>51開發大型嵌入式程序

    Keil5中C51和MDK共存的方法(以Keil5為例)

    Keil5中C51和MDK共存的方法(以Keil5為例)
    發表于 12-03 20:21 ?75次下載
    <b class='flag-5'>Keil</b>5中<b class='flag-5'>C</b>51和MDK共存的<b class='flag-5'>方法</b>(以<b class='flag-5'>Keil</b>5為例)

    Keil MDK與Keil C51共存的方法(成功)

    Keil5+Keil4共存的方法。在網上搜的資料MDK與KeilC51安裝順序都搞反了,但是用此安裝方法可以成功解決了MDK與KeilC51的共存問題。所有功能完美運行。注意事項因為MDK功能比KeilC51多,所以要先安裝Ke
    發表于 12-03 20:36 ?46次下載
    <b class='flag-5'>Keil</b> MDK與<b class='flag-5'>Keil</b> <b class='flag-5'>C</b>51共存的<b class='flag-5'>方法</b>(成功)