std :: list,std :: vector方法和malloc()

Bar*_*hLi 3 c++ stl

在中断处理程序下使用stl:list和stl :: vector类型我想避免malloc()调用.

问题:在STL列表和向量中阻止malloc()调用的最佳方法是什么?是否足以创建具有预定义大小的结构,然后避免推/弹/擦除调用?

先感谢您

Mar*_*age 14

STL容器喜欢std::list并且std::vector具有接受Allocator类型的构造函数.通过提供自己的分配器而不是使用默认值,您可以控制容器分配内存的方式.很少使用此选项,但在实时环境中使用您自己的分配器是此功能有用的一个很好的示例(并证明STL的设计人员做得非常好).

自定义分配器类型的要求在C++标准的 20.1.6中描述


bk1*_*k1e 7

听起来你想在初始化代码中预先分配内存,这样你的中断处理程序就可以避免堆分配.我假设您存储在这些容器中的元素本身不执行任何堆分配,因为这会使答案复杂化.

您可以std::vector通过调用reserve()方法来预分配内存.类似的方法push_back(),pop(),insert()erase()操纵向量的大小(它目前包含元素的个数).当新尺寸大于当前容量时,它们仅影响容量(它有空间的元件数量).reserve(x)确保容量大于或等于x,必要时增加容量.(另请注意,唯一减少矢量容量的操作是swap(),因此您不必担心erase()减少矢量的容量.)

这种方法不起作用std::list,但还有另一种方法:通过将列表元素插入"备用"列表来预分配列表元素.不使用插入新元素,而是使用该splice()方法将它们从"备用"列表移动到"主要"列表.而不是擦除元素,使用该splice()方法将它们从"主"列表移动到"备用"列表.


lea*_*der 4

作为证明:我们在我的工作场所使用其他答案中提到的两种方法:

  • 自定义分配器:对于我们的内存泄漏跟踪系统、我们的仪器分析器和一些其他系统,我们使用提供的分配器进行预分配和/或“池”(参见例如 boost::pool)分配——通常用于 std::set 或std::map,但是std::list的原理是一样的。
  • 保留/调整大小:对于 std::vectors,我们提前保留或调整大小(区别很重要,但两者都可以帮助避免将来的分配)是很常见的做法。

大多数情况下,我们做这两件事是为了避免碎片、减少分配器开销、消除增长时复制的惩罚等。但有时(特别是使用仪器分析器)我们希望绝对避免在中断处理程序期间进行分配。

然而,通常我们会通过其他方式避免中断和分配问题:

  • 进入/退出:在中断期间尽量避免做除设置标志或琐碎副本之外的任何事情;有时静态(或预分配)缓冲区是比 STL 容器更好的解决方案。保持中断时间过长通常会导致灾难。
  • 在分配/释放期间禁用中断:当我们分配/释放时,中断会排队,而不是立即分派——这是我们正在使用的CPU的一个功能。结合有选择地增加禁用/排队范围的策略(例如 std::list 操作),我们有时可以摆脱中断处理程序作为生产者、一切其他作为消费者的模型,而无需覆盖分配器。如果我们正在使用 std::list 中的某些内容(例如从网络硬件接收到的消息),则中断会在尽可能短的时间内排队,同时弹出我们将要处理的内容的副本。

请注意,无锁数据结构可以作为此处第二个项目的替代方案,我们尚未设置并进行分析以查看它是否有帮助。无论如何,设计自己的产品是一件棘手的事情。

对于中断处理程序来说,偏执是勇敢的一部分:如果您不确定自己正在做的事情是否有效,有时以完全不同的方式解决问题会更好。