什么是嵌入式系统的好 C 内存分配器? [关闭]

Posted

技术标签:

【中文标题】什么是嵌入式系统的好 C 内存分配器? [关闭]【英文标题】:What's a good C memory allocator for embedded systems? [closed] 【发布时间】:2010-09-15 16:29:34 【问题描述】:

我有一个单线程嵌入式应用程序,它分配和释放大量的小块 (32-64b)。基于缓存的分配器的完美场景。虽然我可以尝试写一个,但它可能会浪费时间,并且没有像已经在前线的一些解决方案那样经过测试和调整。

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

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

【问题讨论】:

【参考方案1】:

我参加聚会有点晚了,但我只想分享我最近发现并测试的嵌入式系统的非常高效的内存分配器:https://github.com/dimonomid/umm_malloc

这是一个专门设计用于 ARM7 的内存管理库,我个人在 PIC32 设备上使用它,但它应该适用于任何 16 位和 8 位设备(我计划在 16 位 PIC24 上进行测试) ,但我还没有测试过)

我被默认分配器的碎片严重击败:我的项目经常分配各种大小的块,从几个字节到几百个字节,有时我遇到“内存不足”错误。我的 PIC32 设备共有 32K 的 RAM,其中 8192 字节用于堆。在特定时刻有超过 5K 的可用内存,但默认分配器的最大非碎片内存块只有大约 700 字节,因为碎片。这太糟糕了,所以我决定寻找更有效的解决方案。

我已经知道一些分配器,但它们都有一些限制(例如块大小应该是 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

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

【讨论】:

这是最好的答案。感谢您的链接!如果您有兴趣,还可以查看我的内存管理器:github.com/cloudformdesign/tinymem 我已经设计它来处理碎片:)【参考方案2】:

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

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

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

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

最终,当用户请求清理未使用的内存时,我们还改进了系统以包括垃圾收集。由于我们可以控制整个系统,因此我们能够随着时间的推移进行各种优化以提高系统的性能。正如我所提到的,它确实运作良好。

【讨论】:

【参考方案3】:

我最近对这个主题进行了一些研究,因为我们遇到了内存碎片问题。最后,我们决定继续使用 GNU libc 的实现,并在必要时添加一些应用程序级内存池。还有其他分配器具有更好的碎片行为,但我们对它们在全局范围内替换 malloc 感到不够满意。 GNU 拥有悠久的历史。

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

【讨论】:

为此目的使用了 Loki,一切都很好,而且花费的时间很少 Chris,您愿意与内存池共享 glibc malloc 修改版本的代码吗?【参考方案4】:

虽然我问这个问题已经有一段时间了,但我的最终解决方案是使用 LoKi 的 SmallObjectAllocator,它工作得很好。摆脱了所有操作系统调用并提高了我的 Lua 引擎在嵌入式设备上的性能。非常漂亮和简单,只需大约 5 分钟的工作时间!

【讨论】:

【参考方案5】:

由于version 5.1,Lua 允许在creating new states 时设置custom allocator。

【讨论】:

【参考方案6】:

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

【讨论】:

非常好!我忘记了,但这正是我在 GameBoy 上编程时所做的【参考方案7】:

我在vxworks下使用'binary buddy'系统效果不错。基本上,您通过将块切成两半来分配堆,以获得两个大小块的最小功率来保存您的请求,并且当块被释放时,您可以向上传递树以将块合并在一起以减少碎片。谷歌搜索应该会找到您需要的所有信息。

【讨论】:

【参考方案8】:

我正在编写一个名为 tinymem 的 C 内存分配器,旨在能够对堆进行碎片整理并重新使用内存。看看吧:

https://github.com/vitiral/tinymem

注意:该项目已停止进行 rust 实现:

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

另外,我以前没有听说过 umm_malloc。不幸的是,它似乎无法处理碎片,但它确实看起来很有用。我得去看看。

【讨论】:

以上是关于什么是嵌入式系统的好 C 内存分配器? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

C语言中内存分配

C语言中动态内存分配函数的用法及作用?(比如malloc,calloc,realloc等)

C语言中内存分配 (转)

corba的好替代品[关闭]

嵌入式内存管理

linux有什么静态分析C代码的好工具么