如何在PIC中使用 malloc()
和 free()
函數?我檢查了 stdlib.h
標頭和我正在使用MCC18。
有人需要使用它們嗎?
我需要它們,因為我正在將庫從Windows XP移植到PIC。移植指南說
使操作系統的特定功能適應我的PIC功能
,但是我不知道如何“翻譯” malloc()
和 free()
函數。
如何在PIC中使用 malloc()
和 free()
函數?我檢查了 stdlib.h
標頭和我正在使用MCC18。
有人需要使用它們嗎?
我需要它們,因為我正在將庫從Windows XP移植到PIC。移植指南說
使操作系統的特定功能適應我的PIC功能
,但是我不知道如何“翻譯” malloc()
和 free()
函數。
malloc()
通常被認為是“壞事”。但是,如果您絕對需要它,那麼您將需要找到第三方版本。
如果幸運的話,您要移植的代碼可能不依賴於重用內存塊。如果是這種情況,您可以編寫一個簡單的分配器,該分配器將指針返回到RAM緩衝區中,然後將指針前進所需的塊大小。
在移植PC庫之前,我已經成功使用了這種方法
下面,您將使用 my_malloc_init()
設置分配器,並使用 my_malloc()
分配內存。 my_free()
可以滿足依賴關係,但實際上不會做任何事情。當然,最終您會用完空間。
要實現此目的,您需要測量代碼的最壞情況下的內存需求(如果可能,請在PC上執行此操作),然後進行設置相應地 HEAP_SIZE
。在進入需要動態內存的庫部分之前,請調用 my_malloc_init()
。重複使用之前,請確保沒有任何內容指向 heap
。
uint8_t堆[HEAP_SIZE]; uint8_t * heap_ptr; void my_malloc_init(void){ } void * my_malloc(size_t len){uint8_t * p = heap_ptr; heap_ptr + = len;如果(heap_ptr > =堆+ HEAP_SIZE)返回NULL;否則返回p;} void my_free(void){//不執行任何操作}
(注意:在現實世界中,您可能需要考慮指針對齊,即,將舍入(2或4個字節的heap_ptr
)
另一個選擇是使用比 malloc()
通常提供的更簡單的分配結構,例如 FreeList,儘管這可能不允許您分配可變大小的塊。
這幾乎不能回答您的問題,但是動態內存分配通常在小型RAM環境中並且在沒有操作系統的情況下(例如在微控制器世界中)不受歡迎。您在嵌入式系統中擁有的堆空間環境通常以數百個字節為單位進行度量...
實施malloc和free本質上是對“自由段”結構的鍊錶的維護,並且您可以想像,與自由段關聯的元數據不是與通常可用的內存量相比,這是微不足道的...這是管理動態內存池的“開銷”,消耗了大量的可用資源。
我不知道C18標準庫是否支持 malloc
和 free
,但是 Microchip應用筆記AN914顯示瞭如何實現您的
在任何情況下,Thomas和其他張貼者都建議,在具有非常小RAM空間的PIC上使用動態內存充滿了危險。由於缺少更高級的虛擬內存管理器,而這些管理器無法充分發揮OS的作用,因此您可能會很快耗盡連續的空間,從而導致分配失敗和崩潰。更糟糕的是,它可能不是確定性的,調試起來可能會很痛苦。在一些非常特殊的情況下分配空間,我可以看到 malloc
和 free
是可以接受的。
在許多應用程序中,將需要分配內存,但是在保留分配後的內容的同時不需要釋放任何內容。在這樣的系統上,所有需要做的就是使用鏈接器使用所有可用的RAM定義一個數組,設置一個指向該數組開頭的指針,然後使用一個簡單的malloc函數:
char * next_alloc; void * malloc(int size){char * this_alloc; this_alloc = next_alloc;如果(((END_OF_ALLOC_SPACE-this_alloc)<大小)返回-1; next_alloc + =大小; return this_alloc;} void free(void * ptr){if(ptr)next_alloc =(char *)ptr;}
很簡單,對於任何數量的分配,總開銷只有兩個字節。在一個塊上調用free()將釋放該塊及其後的所有內容。
可以通過使用兩個指針來處理稍微更複雜的分配模式:一個指針從向上移動的內存底部分配內容,其中之一是從內存頂部向下。如果堆中的數據是同質的並且知道所有外部引用在哪裡,也可以使用壓縮垃圾收集器。
那麼,您的PIC在內存方面有多大?
malloc是非常分配內存的低效方式。它的問題在於,內存可能會由於頻繁的釋放和malloc而變得碎片化,而只有幾千字節的內存,分配失敗非常普遍。很可能,如果您使用的是較小的芯片或較早的PIC18,則不支持malloc,因為Microchip認為實現起來非常困難(在某些情況下甚至是不可能的),或者使用起來不夠用值得。更不用說了,但是它也相當慢,您正在使用一個可用的靜態緩衝區來查看1個週期,並使用100到1,000個週期來進行malloc。
如果要分配靜態地,創建諸如sprintf函數的緩衝區(如果有的話,大約128字節),SD卡的緩衝區(如果有的話)之類的東西,直到您不再需要malloc。理想情況下,僅在絕對需要它的地方使用它,並且無法擺脫靜態分配,但是這些情況通常很少見,這也許表明您應該在研究更大或更強大的微控制器。
而且,如果您正在PIC18上開發/移植“操作系統”,並且如果它支持微控制器,則它可能支持靜態分配。例如,SQLite3支持靜態分配-您為它分配一個大的緩衝區數組,即使不是微控制器,它也會在可能的情況下使用它。如果不是,那麼您確定它是為小型PIC18設計的嗎?
如果您正在考慮將 malloc()
和 free()
用於嵌入式軟件,建議您看一下uC / OS-II和 OSMemGet( )
和 OSMemPut()
。使用 malloc()
可以分配任意的內存塊,而 OSMem *()
可以為您提供來自預分配池的固定大小的塊。我發現這種方法在 malloc()
的靈活性和靜態分配的魯棒性之間取得了很好的平衡。
AFAIK,要正確執行此操作,您確實需要查看具有某種內存管理單元(MMU)的設備。儘管確實存在PIC18系列的動態分配機制,但它們的作用並不會那麼牢固-就像說有人致力於突破PIC18系列極限的固件一樣,我可以說您不會
更好的解決方案:嘗試了解它在做什麼以及為什麼需要動態分配。看看您是否無法重構它以使用靜態分配。 (在某些情況下,這根本是不可能的-如果庫/應用程序被設計為執行可自由縮放的操作,或者沒有可以接受的輸入量的界限。)但是有時,如果您確實認為關於您要執行的操作,您可能會發現有可能(甚至可能很容易)使用靜態分配。