[英]Decrease memory allocations C++
我遇到了一個麻煩,想出一個好的策略來減少以下問題的內存分配:
我正在建造一棵樹。 開始時,我只有包含一些數據的根(索引的列表( 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();
}
如果每個節點必須自己維護一個動態列表,則可以在調用所有push_back()
之前使用std::vector::reserve()
。
但是,如果在設置根節點后確定了整個長度,並且初始向量保持不變,然后只是在每個節點之間“拆分”,則節點本身可以簡單地將指針指向初始向量內的數據,從而消除了圍繞該數據結構的幾乎所有分配。
基本上,如果您不能基於某些啟發式reserve
向量, 則將成為Schlemiel算法的犧牲品(盡管版本更溫和,因為幾何增長確保n
個連續插入的時間復雜度為O(n)而不是O(n ^ 2))。
但是,如果首先瀏覽該節點的索引並記錄給定的索引是應到達左側子節點,右側子節點還是同時到達這兩個節點,則可以避免分配數量恆定的情況。 還要跟蹤左/右子節點的索引計數:
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]);
}
這樣,您僅執行3個分配,即foo
, leftNodes
和rightNodes
。 盡管您必須兩次遍歷索引,但是繁重的工作(幾何計算)僅在第一個循環中完成。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.