我有一个单线程的嵌入式应用程序,可以分配和释放大量的小块(32-64b).基于缓存的分配器的完美方案.虽然我可以尝试写一个,但这可能是浪费时间,而不是像一些已经在前线的解决方案那样经过测试和调整.
那么我可以用于这种情况的最佳分配器是什么?
注意:我在系统中使用Lua虚拟机(这是80%以上的分配的罪魁祸首),所以我不能轻易地重构我的代码以使用堆栈分配来提高分配性能.
在CI过去的一个项目中,我们为在包括嵌入式系统在内的各种平台上运行的库实现我们自己的内存管理例程迈进了一条路.该库还分配并释放了大量小缓冲区.它运行得相对较好,并没有采用大量代码来实现.如果你想自己开发一些东西,我可以给你一些关于该实现的背景知识.
基本实现包括一组管理设置大小的缓冲区的例程.这些例程被用作malloc()和free()的包装器.我们使用这些例程来管理我们经常使用的结构的分配,以及管理集合大小的通用缓冲区.结构用于描述被管理的每种类型的缓冲区.当分配了特定类型的缓冲区时,我们将malloc()块中的内存(如果空闲缓冲区列表为空).IE,如果我们管理10个字节的缓冲区,我们可能会生成一个malloc(),其中包含100个这些缓冲区的空间,以减少碎片和所需的底层malloc数量.
在每个缓冲区的前面将是一个指针,用于链接空闲列表中的缓冲区.当分配100个缓冲区时,每个缓冲区将在空闲列表中链接在一起.使用缓冲区时,指针将设置为null.我们还维护了缓冲区"块"的列表,这样我们就可以通过在每个实际的malloc缓冲区上调用free()来进行简单的清理.
为了管理动态缓冲区大小,我们还在每个缓冲区的开头添加了一个size_t变量,告诉缓冲区的大小.然后使用它来识别哪个缓冲区块在释放时将缓冲区放回.我们有malloc()和free()的替换例程,它们使用指针算法来获取缓冲区大小,然后将缓冲区放入空闲列表中.我们对我们管理的缓冲区数量也有限制.大于此限制的缓冲区只是malloc'd并传递给用户.对于我们管理的结构,我们创建了用于分配和释放特定结构的包装程序.
最后,当用户请求清理未使用的内存时,我们还将系统演变为包括垃圾收集.由于我们可以控制整个系统,因此我们可以随着时间的推移进行各种优化以提高系统性能.正如我所提到的,它确实运作良好.
我最近对这个话题进行了一些研究,因为我们遇到了内存碎片问题.最后,我们决定继续使用GNU libc的实现,并在必要时添加一些应用程序级内存池.还有其他分配器具有更好的碎片行为,但是我们对它们在全球范围内替换malloc不够舒服.GNU的背后有着悠久的历史.
在你的情况下,它似乎是合理的; 假设您无法修复VM,那些微小的分配非常浪费.我不知道你的整个环境是什么,但是你可以考虑在VM上包含对malloc/realloc/free的调用,这样你就可以把它传递给专为小池设计的处理程序.
我参加派对有点晚了,但我只是想为我最近发现和测试的嵌入式系统分享非常有效的内存分配器: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?update = snn.mios32&path =%2Ftrunk%2FFreeRTOS%2FSource%2Fportable%2FMemMang%2F&verv = 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
我相信任何需要为微控制器提供高效内存分配器的人,至少应该尝试这一点.
虽然我问过这个问题已经过了一段时间,但我最后的解决方案是使用LoKi的SmallObjectAllocator它非常有用.摆脱了所有操作系统调用,提高了我的嵌入式设备Lua引擎的性能.非常好,简单,只需要大约5分钟的工作!
从版本5.1开始,Lua允许在创建新状态时设置自定义分配器.