如何在PIC中使用malloc()
和free()
运行?我检查了stdlib.h
标头,没有任何提及。我正在使用MCC18。
是否有人需要使用它们?
我需要它们,因为我正在将库从Windows XP移植到PIC。移植指南说
使操作系统的特定功能适应我的PIC功能
但是我不知道如何“翻译” malloc()
和free()
功能。
如何在PIC中使用malloc()
和free()
运行?我检查了stdlib.h
标头,没有任何提及。我正在使用MCC18。
是否有人需要使用它们?
我需要它们,因为我正在将库从Windows XP移植到PIC。移植指南说
使操作系统的特定功能适应我的PIC功能
但是我不知道如何“翻译” malloc()
和free()
功能。
Answers:
在许多应用程序中,将需要分配内存,而无需在保留已分配的内容的同时释放任何内容。在这样的系统上,所有需要做的就是使用链接器使用所有可用的RAM定义一个数组,设置一个指向该数组开头的指针,然后使用一个不错的简单malloc函数:
char * next_alloc; 无效* malloc(int size) { 字符* this_alloc; this_alloc = next_alloc; 如果((END_OF_ALLOC_SPACE-this_alloc)<大小) 返回-1; next_alloc + =大小; 返回this_alloc; } 无空(void * ptr) { 如果(ptr) next_alloc =(char *)ptr; }
简单易用,任何数量的分配仅需要两个字节的总开销。在块上调用free()将取消分配该块及其后的所有内容。
可以通过使用两个指针来处理稍微复杂一些的分配模式-一个指针从向上移动的内存底部分配内容,另一个指针从向下移动的内存顶部分配内存。如果堆中的数据是同质的并且知道所有外部引用在哪里,也可以使用压缩垃圾收集器。
malloc()
在微控制器中通常被认为是“坏事”。但是,如果您绝对需要它,那么您将需要找到第三方版本。
如果幸运的话,要移植的代码可能不依赖于重用内存块。在这种情况下,您可以编写一个简单的分配器,该分配器将指针返回到RAM缓冲区中,然后将指针前进所需的块大小。
在将PC库移植到微控制器之前,我已经成功使用了这种方法。
在下面,您将使用设置分配器,my_malloc_init()
并使用分配内存my_malloc()
。my_free()
是否在那里满足依赖关系,但实际上什么也不会做。最终,您当然会用完空间。
要使此工作正常进行,您需要测量代码的最坏情况下的内存需求(如果可能,请在PC上执行此操作),然后进行相应的设置HEAP_SIZE
。在进入需要动态内存的库部分之前,请致电my_malloc_init()
。在重复使用之前,请确保没有任何东西指向heap
。
uint8_t heap[HEAP_SIZE];
uint8_t *heap_ptr;
void my_malloc_init(void)
{
heap_ptr = heap;
}
void *my_malloc(size_t len)
{
uint8_t *p = heap_ptr;
heap_ptr += len;
if (heap_ptr >= heap + HEAP_SIZE)
return NULL;
else
return p;
}
void my_free(void)
{
// do nothing
}
(注意:在现实世界中,您可能需要考虑指针对齐,即四舍五入heap_ptr
为2或4个字节)
另一种选择是使用比malloc()
通常提供的更简单的分配结构,例如FreeList,尽管这可能不允许您分配可变大小的块。
这几乎不能回答您的问题,但是动态内存分配通常在小型RAM环境中并且在没有操作系统(例如在微控制器世界中)的情况下不受欢迎。通常,嵌入式环境中可用的堆空间通常是以数百个字节为单位...
实现malloc和free本质上是对“空闲段”结构的链表的维护,并且您可以想象,与空闲段相关联的元数据与通常可用的内存量相比并不算是虚假的……这是“开销”管理动态内存池”会消耗大量可用资源。
我不知道C18标准库是否支持malloc
和free
,但是Microchip应用笔记AN914展示了如何实现自己的。
在任何情况下,托马斯和其他海报建议,采用动态内存的PIC与他们的非常小的RAM空间充满了危险。由于缺少更高级的虚拟内存管理器,而这些虚拟内存管理器无法充分发挥操作系统的作用,从而导致分配失败和崩溃,因此您可能会很快耗尽连续的空间。更糟糕的是,它可能不是确定性的,并且可能很难调试。
如果您正在做的事情是在运行时真正动态确定的(对于大多数嵌入式事物来说是很少的),并且您只需要在几个非常特殊的情况下分配空间,我就会发现malloc
并且free
可以接受。
那么,您的PIC在内存方面有多大?
malloc是分配内存的一种非常低效的方式。这样做的问题是,频繁的释放和malloc可能使内存变得碎片化,而只有几千字节的内存,分配失败非常普遍。很可能,如果您使用的是较小的芯片或较早的PIC18,则不支持malloc,因为Microchip认为实现起来非常困难(在某些情况下甚至是不可能的),或者使用起来不够用。值得。更不用说了,但是它也相当慢,您正在寻找使用一个可用的静态缓冲区的1个周期,以及执行malloc的100至1,000个周期。
如果要静态分配,则创建诸如sprintf函数的缓冲区(如果有的话,大约128字节),SD卡的缓冲区(如果有的话)之类的东西,直到您不再需要malloc。理想情况下,仅在绝对需要它的地方使用它,并且无法摆脱静态分配,但是这些情况通常很少见,这也许表明您应该考虑使用更大或更强大的微控制器。
而且,如果您正在PIC18上开发/移植“操作系统”,并且如果它支持微控制器,则它可能支持静态分配。例如,SQLite3支持静态分配-您为它分配一个大的缓冲区数组,即使不是微控制器,它也会在可能的情况下使用它。如果不是,那么您确定它是为小型PIC18设计的吗?
AFAIK,要正确执行此操作,您确实需要查看具有某种内存管理单元(MMU)的设备。尽管确实存在PIC18系列的动态分配机制,但它们的作用并不会那么牢固-就像说有人致力于突破PIC18系列极限的固件一样,我可以说您不会如果您将所有开销都花在了内存管理器上,那么其中就有一个相当大的应用程序。
更好的解决方案:尝试了解它在做什么以及为什么需要动态分配。查看您是否无法重构它以使其与静态分配一起使用。(在某些情况下,这根本是不可能的-如果库/应用程序被设计为执行可自由缩放的操作,或者没有可以接受的输入量的界限。)但是有时,如果您确实认为关于您要执行的操作,您可能会发现有可能(甚至可能很容易)使用静态分配。