我应该使用什么c++ STL类来减少由大量小分配引起的碎片

What C++ STL class should I use to reduce fragmentation caused by lots of small allocations?

本文关键字:分配 碎片 什么 c++ STL 我应该      更新时间:2023-10-16

我的c++类构建了一个树形结构。树中的每个节点当前都是在构造时分配的(使用new)。节点类只使用几个字节的内存。随着树的生长,可能会有10万个节点;树的最大节点数是未知的,除了理论最大值2^33。我通过指针引用树结构中的节点。当树被破坏时,所有节点都被释放。

我是一个标准库容器或内存分配器/池,我可以用它来分配和存储节点在我的树类,以减少内存碎片和内存分配开销。我希望避免编写自定义分配器。容器应该有以下两个属性:

  1. 分配的对象不会在内存中移动,因此可以安全地被指针引用。
  2. 类为大块对象分配内存,从而减少内存碎片。请注意,我做而不是要求整个容器在内存中是连续的。

我不需要容器的迭代器或查找功能,因为我的树结构存储指针。什么样的标准库类将为我提供这个功能,并给我最低的内存开销?

由于您特别要求标准容器,因此根据您的需求,std::deque是最有希望的选择。只要只添加元素,现有的元素就不会被重新定位,并且引用/指针(但而不是迭代器)仍然有效。当移除元素时,你可能需要留下空白,或者与最后一个元素交换要移除的元素。

std::vector不稳定,std::liststd::forward_list以及所有的结合容器都是碎片化的。

看Boost。容器中,您有额外的选择,但是有其他权衡:

  • boost::flat_map提供连续存储(像std::vector),但它的稳定性问题
  • boost::stable_vector以牺牲相邻性为代价提供了元素稳定性。

或者,您可以查看池分配器(如Boost.Pool)。它们提供了低碎片和快速分配,并且它前面的容器仍然可以像普通容器一样使用。

当您通过指针引用树结构中的节点时(因此,它们不应该被重新分配),并且希望减少内存碎片,我建议为Node对象使用内存池。

提振。池库可以满足您的需求。

的例子:

class Tree
{
    Tree() : nodesPool_(new boost::object_pool<Node>()) {}
    void CreateNode(nodeArg1, nodeArg2, ...)
    {
        Node * node = nodesPool_->construct(nodeArg1, nodeArg2, ...);
        ...
    }
    std::unique_ptr<boost::object_pool<Node>> nodesPool_;
};

您所描述的听起来就像std::deque所做的。还可以查看这篇比较vector和deque

的文章。

恐怕你在你想要实现的事情上加了很多限制。

可能尝试使用的是vector。它是(除了array和可能我错过的其他人)唯一可能在一个块中分配对象的标准容器。

但是这里有一个问题,当vector增长时,不能保证对象将继续保持在相同的地址上。如果你不调整vector的大小(或使用array不能增长),这是一个很好的可能性,你是安全的。

否则,通常的过程是编写一个自定义分配器,该分配器使用一个对象池来完成分配。此外,您必须注意您的树不会为每个节点分配数据块。

您可能想要考虑的另一种选择是使用std::vector,但在节点上保留索引而不是指针。这样你甚至可以获得一些内存,因为你可以存储32位索引而不是64位指针,这取决于你的体系结构和需要。

它要求节点当然可以被复制或移动