題:
在PIC中使用malloc
stef
2010-12-14 20:34:25 UTC
view on stackexchange narkive permalink

如何在PIC​​中使用 malloc() free()函數?我檢查了 stdlib.h 標頭和我正在使用MCC18。

有人需要使用它們嗎?

我需要它們,因為我正在將庫從Windows XP移植到PIC。移植指南說

使操作系統的特定功能適應我的PIC功能

,但是我不知道如何“翻譯” malloc() free()函數。

如果可能,請嘗試使用靜態分配。
為什麼?問題確實是我正在寫一個相當大的庫的底層(特定於平台的那一層),並且有很多函數,我不知道它們的用途是什麼..而且我也不知道如何從中更改動態到靜態
聽起來像是RAM <4KB的PIC單片機可能對您的應用是錯誤的。在PC上,在開始端口之前測量PC庫的內存使用情況。使用功能更強大的ARM Cortex-M3之類的產品可能會更好。經驗法則:如果您要移植的代碼庫太大而無法理解,那麼它將不適合PIC。
Windows驅動程序(和一般的應用程序)基本上是用“無限RAM”範例編寫的,因為如果物理RAM用完了,則可以交換虛擬內存。根據庫的工作情況,它可能會消耗比4kB更多的內存可在PIC18F87J11中使用。我懷疑您將無法衡量驅動程序將要使用多少內存。
另一個潛在的問題:Win32 int是32位,而使用MCC18編譯器時,它只有16位。如果不小心,可能會出現奇怪的溢出問題。
大多數係統上的內核驅動程序絕對是“不”用“無限RAM”範例編寫的。內核的內部存儲器通常不分頁,因為這是導致死鎖的秘訣。
七 答案:
Toby Jaffey
2010-12-15 02:28:44 UTC
view on stackexchange narkive permalink
微控制器中的

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,儘管這可能不允許您分配可變大小的塊。

我不知道何時將malloc視為嵌入式的好東西。
我仍然同意您不希望像其他人所說的那樣在程序中進行動態分配,但這是實現它的一種好方法。到目前為止,為嵌入式設計的第三方malloc是最佳選擇。必須避免分段。 @jobyTaffey寫得很好。
@Kellenjb很好,這是一個全新的問題:-)
我建議my_free應該將heap_ptr設置為傳入的值,從而有效地釋放所指示的項以及在其之後分配的所有內容。顯然,必須以允許這種用法的順序分配事物,但是這種模式並不少見。另一個有用的變化是擁有兩對alloc / free函數,其中一對分配自上而下的分配,而另一對分配自下而上的分配。
vicatcu
2010-12-14 21:09:59 UTC
view on stackexchange narkive permalink

這幾乎不能回答您的問題,但是動態內存分配通常在小型RAM環境中並且在沒有操作系統的情況下(例如在微控制器世界中)不受歡迎。您在嵌入式系統中擁有的堆空間環境通常以數百個字節為單位進行度量...

實施malloc和free本質上是對“自由段”結構的鍊錶的維護,並且您可以想像,與自由段關聯的元數據不是與通常可用的內存量相比,這是微不足道的...這是管理動態內存池的“開銷”,消耗了大量的可用資源。

在某些實現中,元數據開銷非常小。對於分配的塊,您僅需要其大小。對於未使用的塊,即使具有相當合理的最小塊大小,通常也可以免費使用鏈接列表指針。
使用微控制器的小型,長期運行的系統通常與元數據無關,而與內存碎片有關。更糟糕的是,對代碼進行小的更改可能會導致內存碎片化,而以前則是零碎的,因此您可能會做出看起來很無辜的更改,從而突然使程序停止“過早地工作”。
Nick T
2010-12-14 20:52:30 UTC
view on stackexchange narkive permalink

我不知道C18標準庫是否支持 malloc free ,但是 Microchip應用筆記AN914顯示瞭如何實現您的

在任何情況下,Thomas和其他張貼者都建議,在具有非常小RAM空間的PIC上使用動態內存充滿了危險。由於缺少更高級的虛擬內存管理器,而這些管理器無法充分發揮OS的作用,因此您可能會很快耗盡連續的空間,從而導致分配失敗和崩潰。更糟糕的是,它可能不是確定性的,調試起來可能會很痛苦。在一些非常特殊的情況下分配空間,我可以看到 malloc free 是可以接受的。

連續內存不足(也就是堆碎片)是一個完全獨立於地址空間大小以及是否具有虛擬內存的問題。您可能需要權衡一些浪費的RAM以減少堆碎片,但是最終,在長時間運行的系統上,您無法保證不會用完堆空間。小型系統和大型系統之間的唯一區別是,磁盤開始抖動需要多長時間(在具有分頁VM的系統上),或者分配器返回NULL(在嵌入式系統中)。
-1
@supercat您說得對。確實,我太過戲劇化了。有這些保證的正式證明。
supercat
2011-02-24 03:00:26 UTC
view on stackexchange narkive permalink

在許多應用程序中,將需要分配內存,但是在保留分配後的內容的同時不需要釋放任何內容。在這樣的系統上,所有需要做的就是使用鏈接器使用所有可用的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()將釋放該塊及其後的所有內容。

可以通過使用兩個指針來處理稍微更複雜的分配模式:一個指針從向上移動的內存底部分配內容,其中之一是從內存頂部向下。如果堆中的數據是同質的並且知道所有外部引用在哪裡,也可以使用壓縮垃圾收集器。

要完全了解可能性,請閱讀以下網址的答案:https://electronics.stackexchange.com/questions/7850/use-of-malloc-in-pic#answer-7871
Thomas O
2010-12-14 20:53:18 UTC
view on stackexchange narkive permalink

那麼,您的PIC在內存方面有多大?

malloc是非常分配內存的低效方式。它的問題在於,內存可能會由於頻繁的釋放和malloc而變得碎片化,而只有幾千字節的內存,分配失敗非常普遍。很可能,如果您使用的是較小的芯片或較早的PIC18,則不支持malloc,因為Microchip認為實現起來非常困難(在某些情況下甚至是不可能的),或者使用起來不夠用值得。更不用說了,但是它也相當慢,您正在使用一個可用的靜態緩衝區來查看1個週期,並使用100到1,000個週期來進行malloc。

如果要分配靜態地,創建諸如sprintf函數的緩衝區(如果有的話,大約128字節),SD卡的緩衝區(如果有的話)之類的東西,直到您不再需要malloc。理想情況下,僅在絕對需要它的地方使用它,並且無法擺脫靜態分配,但是這些情況通常很少見,這也許表明您應該在研究更大或更強大的微控制器。

而且,如果您正在PIC18上開發/移植“操作系統”,並且如果它支持微控制器,則它可能支持靜態分配。例如,SQLite3支持靜態分配-您為它分配一個大的緩衝區數組,即使不是微控制器,它也會在可能的情況下使用它。如果不是,那麼您確定它是為小型PIC18設計的嗎?

我明白你的意思了。我正在使用PIC18F87J11,它具有128K的ram,足夠嗎?
Stefano,該芯片具有3,904字節的RAM。它具有128K的程序閃存。
-1
對不起..您認為還是可以嗎?
@Stefano Salati,無需道歉。我認為您會真正做到這一點。它可能會起作用,但會浪費大量性能和可用內存。
當然,@Stefano,可以煮一杯咖啡。要乘坐787?沒有。
trondd
2010-12-17 05:09:27 UTC
view on stackexchange narkive permalink

如果您正在考慮將 malloc() free()用於嵌入式軟件,建議您看一下uC / OS-II和 OSMemGet( ) OSMemPut()。使用 malloc()可以分配任意的內存塊,而 OSMem *()可以為您提供來自預分配池的固定大小的塊。我發現這種方法在 malloc()的靈活性和靜態分配的魯棒性之間取得了很好的平衡。

andersop
2010-12-20 05:37:49 UTC
view on stackexchange narkive permalink

AFAIK,要正確執行此操作,您確實需要查看具有某種內存管理單元(MMU)的設備。儘管確實存在PIC18系列的動態分配機制,但它們的作用並不會那麼牢固-就像說有人致力於突破PIC18系列極限的固件一樣,我可以說您不會

更好的解決方案:嘗試了解它在做什麼以及為什麼需要動態分配。看看您是否無法重構它以使用靜態分配。 (在某些情況下,這根本是不可能的-如果庫/應用程序被設計為執行可自由縮放的操作,或者沒有可以接受的輸入量的界限。)但是有時,如果您確實認為關於您要執行的操作,您可能會發現有可能(甚至可能很容易)使用靜態分配。

你不對MMU允許您與外部存儲器接口(可能比PIC上的4kB多)。帶有和不帶有MMU的動態和靜態分配幾乎沒有區別。一旦開始進入虛擬內存,就存在區別,但這僅與malloc切向相關。
早期的Macintosh程序員經常使用malloc()和free()(或其Pascal等效項),儘管早期的Macintosh計算機沒有MMU。在我看來,“正確”使用malloc()需要MMU的想法似乎不正確。


該問答將自動從英語翻譯而來。原始內容可在stackexchange上找到,我們感謝它分發的cc by-sa 2.0許可。
Loading...