c++ - 允许堆分配短期范围内的对象以确保内存碎片的自由

标签 c++ embedded heap-memory stack-memory memory-fragmentation

我们在嵌入式系统环境中使用 C++,基本上不需要任何类型的动态内存分配(例如 Resources for memory management in embedded application,我们不这样做的原因)。我们仍然不想没有一些很好的基于 C++ 的特性,例如 STL 容器和 std::string。对于第一个,我们会在初始化时保留一个特定的大小,并且不会让容器超出其容量。对于后者 (std::string),我对如何“安全地”使用它们有点怀疑,因为它们有时会在堆上分配内存。

不过,我发现在某些情况下,使用 std::string(通常还有其他堆分配对象)似乎没问题:我会在堆栈上分配对象本身(在由 {} 分隔的特定范围内,如我说的是 C++)并允许它们分配堆,前提是它们在超出范围时实际上释放了所有保留的内存。

我知道这种方法并不能绝对保证内存碎片的自由,但我觉得如果手头的范围是短暂的,这实际上会在范围结束后导致连续的空闲内存。

我也怀疑当多个任务共享同一个堆但空闲内存最终应该是连续的时可能会出现问题,前提是手头的范围都是短暂的(例如不要阻塞)。或者,我可以接受只允许一个任务在堆上分配内存,而其他任务则不能,如果这真的很重要的话。

我建议的堆分配对象用法有效吗?有人有其他策略(部分)启用动态内存分配而不冒内存碎片的风险吗?

最佳答案

过去,我们在紧凑型嵌入式系统上进行过各种 C++ 风格的动态内存分配。您只需要遵循一些规则并小心混合短期和长期缓冲。首先,内存池是您的 friend - 正如文章所说。

此外,对于 C++ 喜欢在成对和控制结构中进行的所有小(<64 字节)分配,单元分配方案是必不可少的 - 不仅是为了碎片控制,还有性能。单元分配器预分配一些相同大小的内存单元(例如 64 字节)并将它们放在空闲堆栈中。分配内存时,将它们从空闲堆栈中弹出并返回。因为所有大小都是相同的,所以 block 大小只有内部碎片。因为您不必在完成时加入内存,分配和释放是 O(1) 时间。

一些其他规则:如果您需要进行长期动态分配,则不要在它之前进行任何短期分配。先分配大缓冲区,再分配小缓冲区,这样内存就不会分散。另一种系统是将长期分配放在堆的后面,将短期分配放在堆的前面。我们在这方面也取得了成功。

您还可以使用多个堆(池)来隔离不同类型的分配。如果您有一些东西在代码的一部分中创建了一大堆短期分配,而另一部分遵循不同的模式,请给它们一个不同的堆。

如果仔细遵循以上所有内容,将防止或限制碎片化。另一种解决方案是使用可重定位的内存分配系统,其中低优先级线程可以重新排序内存以使其随时间保持连续。我也看到过几次这样做 - 用一点性能换取 0 个长期碎片。

alloca 也有帮助,但如果您没有遵循内存碎片预防方法,您也将结束分散您的堆栈 - 因为这往往是更有值(value)的资源嵌入式土地,这可能不是一个好主意。

关于c++ - 允许堆分配短期范围内的对象以确保内存碎片的自由,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16402059/

相关文章:

c++ - vector insert() 导致程序崩溃

embedded - 如何使用AT命令了解SIM800模块的网络状态?

java - 如何在年轻一代集合中找出 Activity 对象?

c++ - 在启动时运行的 Qt 程序中读取文本文件

python - 使用循环参数生成变量

C++ vector 按值 : did I get it right? 传递

winapi - VirtualAlloc 和 HeapAlloc 有什么区别?

C++ 设置迭代器错误 : no match for ‘operator+=’

c++ - 使用系统调用打开 Outlook 2010 以发送预格式化的电子邮件

c++ - 交换堆栈上的两个值