减少内存分配C ++

时间:2016-02-09 12:44:34

标签: c++ memory-management dynamic-memory-allocation bounding-volume

我遇到了一个很好的策略来减少以下问题的内存分配:

我正在建造一棵树。一开始,我只有一个包含一些数据的根(索引列表(std::vector))。我分成两部分,其中部分索引转到左边的孩子,另一部分转到右边。我不知道有多少人会左/右。有一次,我完成了处理根,我不再需要为它存储索引。事实上,我只对那些叶子感兴趣。此外,每次拆分都可以添加额外的数据! 因此,如果根有20个元素,那么在分割之后,左边的元素可以有12个元素,右边的元素可以有10个元素。

在每个节点中,我保留一个包含这些索引的std::vector。当我添加元素时,我push_back()导致许多内存分配的元素。

保持指数的好策略是什么?

该问题与SBVH数据结构的生成有关。

代码:

struct Node {
     std::vector<unsigned> indices_;
     // ... some other stuff here
}
void partition(Node* node) {
    Node* left = new Node();
    Node* right = new Node();
    float axis = findSplitPosition(node);

    for(size_t i = 0; i < node->indices_.size(); ++i) {
        if (index is strictly left on axis) {
            left->indices_.push_back(node->indices_[i]);
        } else if(index is strictly right on axis) {
            right->indices_.push_back(node->indices_[i]);
        } else {
            // it intersects the axis -> add to left and right
            left->indices_.push_back(node->indices_[i]);
            right->indices_.push_back(node->indices_[i]);
        }
    }

    // root indices no longer needed
    node->indices_.clear();

}

2 个答案:

答案 0 :(得分:3)

如果每个节点都必须自己维护一个动态列表,那么您可以在调用所有push_back()之前使用std::vector::reserve()

但是,如果设置了根并且初始向量保持不变,则确定整个长度,然后您只需将其拆分即可。在每个节点之间,节点本身可以​​简单地保存指向初始向量内部数据的指针 - 从而消除了围绕此数据结构的几乎所有分配。

答案 1 :(得分:0)

基本上如果你不能reserve基于某些启发式的向量,你就会成为Schlemiel's algorithm的受害者(虽然这是一个较温和的版本,因为几何增长确保了{{1}的O(n)时间复杂度连续插入而不是O(n ^ 2))。

但是,如果首先通过节点的索引并记录给定的索引是否应该转到左子节点,右子节点或两者,那么你可以获得恒定数量的分配。还要跟踪左/右子节点的索引计数:

n

这样您只需进行3次分配,即struct Foo { bool goesIntoLeft; bool goesIntoRight; }; std::vector<Foo> foo; foo.reserve(node->_indices.size()); int leftCount = 0; int rightCount = 0; for (auto i = 0; i < node->_indices.size(); ++i) { if (index goes into left) { foo.push_back({ true, false }); ++leftCount; } else if (index goes into right) { foo.push_back({ false, true }); ++rightCount; } else { // goes into both foo.push_back({ true, true }); ++leftCount; ++rightCount; } } std::vector<Node> leftNodes; leftNodes.reserve(leftCount); std::vector<Node> rightNodes; rightNodes.reserve(rightCount); for (auto i = 0; i < node->_indices.size(); ++i) { if (foo[i].goesIntoLeft) leftNodes.push_back(nodes._indices[i]); if (foo[i].goesIntoRight) rightNodes.push_back(nodes._indices[i]); } fooleftNodes。虽然你必须遍历指数两次,但是重量提升(几何计算)只在第一个循环中完成。