2008-10-07 91 views
20

我有一个单线程的嵌入式应用程序,可以分配和取消分配很多很多的小块(32-64b)。基于缓存的分配器的完美场景。尽管我可以尝试写一篇,但这可能会浪费时间,而且还没有经过良好的测试和调整,因为一些解决方案已经在前线。什么是适用于嵌入式系统的C内存分配器?

那么什么是我可以用于这种情况的最佳分配器?

注意:我在系统中使用了一个Lua虚拟机(这是80 +%分配的罪魁祸首),所以我不能轻易重构我的代码以使用堆栈分配来提高分配性能。

回答

7

我最近在这个话题上做了一些研究,因为我们有内存碎片问题。最后,我们决定继续使用GNU libc的实现,并在必要时添加一些应用程序级内存池。还有其他的分配器具有更好的分裂行为,但是我们不满意他们在全球取代malloc。 GNU的背后有着悠久的历史。

在你的情况下,似乎有理由;假设你无法修复虚拟机,那么这些微小的分配是非常浪费的。我不知道你的整个环境是什么,但是你可能会考虑把调用包装到只有虚拟机的malloc/realloc/free上,以便将它传递给为小池设计的处理程序。

+0

为此目的使用Loki,所有的工作都很好,花了很少的时间 – 2008-11-21 01:23:16

+0

克里斯,你愿意分享glibc malloc修改版本的代码与内存池吗? – 2017-04-24 19:16:51

8

在C编写的一个过去的项目中,我们走上了实现我们自己的内存管理例程的道路,该例程适用于运行在包括嵌入式系统在内的各种平台上的库。该库还分配并释放了大量小缓冲区。它运行得相对较好,并且不需要大量的代码来实现。如果你想自己开发一些东西,我可以给你一些背景知识。

基本实现包括一组管理设置大小的缓冲区的例程。这些例程被用作malloc()和free()的包装器。我们使用这些例程来管理我们经常使用的结构的分配,并管理设置大小的通用缓冲区。一个结构被用来描述被管理的每种类型的缓冲区。当分配了特定类型的缓冲区时,我们将malloc()存储在块中(如果空闲缓冲区列表为空)。 IE中,如果我们管理10个字节的缓冲区,我们可能会为包含100个这些缓冲区的空间创建一个malloc(),以减少碎片以及所需的底层malloc数量。

在每个缓冲区的前端会有一个指针,用来链接空闲列表中的缓冲区。当分配100个缓冲区时,每个缓冲区将在空闲列表中链接在一起。当缓冲区正在使用时,指针将被设置为空。我们还维护了一个缓冲区“块”的列表,以便我们可以通过在每个实际的malloc'd缓冲区上调用free()来做一个简单的清理。

为了管理动态缓冲区大小,我们还在每个缓冲区的开始处添加了一个size_t变量,告诉缓冲区的大小。然后这被用来识别哪个缓冲区块在释放时将缓冲区放回。我们有用于malloc()和free()的替换例程,它们执行指针运算来获取缓冲区大小,然后将缓冲区放入空闲列表中。我们也对我们管理的缓冲区有多大限制。大于此限制的缓冲区只是malloc'd并传递给用户。对于我们管理的结构,我们创建了用于分配和释放特定结构的包装例程。

最终我们还演化了系统,以便在用户请求清理未使用的内存时包含垃圾收集。由于我们可以控制整个系统,因此我们可以通过各种优化来提高系统的性能。正如我提到的那样,它确实工作得很好。

6

虽然我问了这个问题有一段时间,但我的最终解决方案是使用LoKi的SmallObjectAllocator,它工作的很好。摆脱了所有的操作系​​统调用并改善了我的Lua引擎对于嵌入式设备的性能。非常好,简单,只需5分钟的工作!

3

我也想补充一点,即使它是一个旧线程。在嵌入式应用程序中,如果您可以分析应用程序的内存使用情况并提供最大数量的不同大小的内存分配,通常最快的分配器类型是使用内存池的分配器。在我们的嵌入式应用程序中,我们可以确定运行时所需的所有分配大小。如果你能做到这一点,你可以完全消除堆碎片并且分配速度非常快。大多数这些实现都有一个溢出池,它会为特殊情况做一个正常的malloc,如果你做了分析的话,这些特殊情况下希望是远远少之又少。

+1

非常好的一点!我忘记了这一点,但这正是我在GameBoy – 2009-07-07 02:17:39

2

我已经在vxworks下使用'binary buddy'系统来取得良好效果。基本上,通过将块切割成一半以获得两块大小最小的块以满足您的要求,当块被释放时,您可以将树合并,将块合并到一起以缓解碎片。谷歌搜索应该会显示你需要的所有信息。

7

我有点迟到了,但我想和大家分享非常高效的内存分配用于嵌入式系统的,我最近发现并测试:https://github.com/dimonomid/umm_malloc

这是一个内存管理库专门设计的,使用ARM7,我个人使用它在PIC32器件上,但它可以在任何16位和8位器件上工作(我计划在16位PIC24上测试,但我还没有测试过)

我被默认分配器的碎片严重殴打:我的项目经常分配不同大小的块,从几个字节到几百个字节,有时我面临'内存不足'的错误。我的PIC32器件总共有32K的RAM,8192字节用于堆。在特定时刻有超过5K的空闲内存,但由于碎片,默认分配程序具有最大非碎片内存块,只有大约700字节。这太糟糕了,所以我决定寻找更有效的解决方案。我已经知道了一些分配器,但它们都有一些限制(例如块大小应该是一个2或2,并且不是从2开始,而是从128个字节开始),或者只是越野车。每次之前,我都不得不切换回默认的分配器。

但是这一次,我很幸运:我发现这一个:http://hempeldesigngroup.com/embedded/stories/memorymanager/

当我试图此内存分配器,在完全相同的情况下的空闲内存5K,有超过3800个字节块!这对我来说太难以置信了(相比700字节),并且我进行了严格测试:设备工作超过30个小时。没有内存泄漏,一切正常,因为它应该工作。 我还在FreeRTOS存储库中发现了这个分配器:http://svnmios.midibox.org/listing.php?repname=svn.mios32&path=%2Ftrunk%2FFreeRTOS%2FSource%2Fportable%2FMemMang%2F&rev=1041&peg=1041#,这个事实是umm_malloc稳定性的另一个证据。 所以我完全切换到了umm_malloc,我对它很满意。

我只是不得不改变它一点:当宏UMM_TEST_MAIN没有被定义时,配置有点麻烦,所以我创建了github库(链接在这篇文章的顶部)。现在,依赖于用户的配置存储在单独的文件umm_malloc_cfg中。h

我在这个分配器中应用的算法还没有深入,但它对算法有非常详细的解释,所以任何有兴趣的人都可以查看umm_malloc.c文件的顶部。至少,“分箱”方法应该在较少的碎片中给予巨大的好处:http://g.oswego.edu/dl/html/malloc.html

我相信任何需要高效的微控制器内存分配器的人都应该试试这个。

-1

我正在写一个名为tinymem的C内存分配器,目的是能够对堆进行碎片整理,并重新使用内存。检查出来:

https://github.com/vitiral/tinymem

注:此项目已停止对锈实施工作:

https://github.com/vitiral/defrag-rs

另外,我没有听说过umm_malloc之前。不幸的是,它似乎无法处理碎片,但它看起来非常有用。我将不得不检查出来。