在他的演讲"Efficiency with algorithms, Performance with data structures"中,Chandler Carruth谈到了在C ++中需要更好的分配器模型。当前的分配器模型侵入了类型系统,因此很难在许多项目中工作。另一方面,Bloomberg allocator model不会侵入类型系统,而是基于虚函数调用,这使得编译器无法“看到”分配并对其进行优化。在他的演讲中,他谈到编译器重复删除内存分配(1:06:47)。
我花了一些时间找到一些内存分配优化的例子,但是我发现这个代码示例在clang下编译,优化了所有内存分配,只返回1000000而不分配任何内容。
template<typename T>
T* create() { return new T(); }
int main() {
auto result = 0;
for (auto i = 0; i < 1000000; ++i) {
result += (create<int>() != nullptr);
}
return result;
}
以下论文http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3664.html也说分配可以在编译器中融合,似乎表明某些编译器已经做过那样的事情。
由于我对高效内存分配的策略非常感兴趣,我真的想了解为什么Chandler Carruth反对Bloomberg模型中的虚拟调用。上面的例子清楚地表明,clang可以在看到分配时优化它们。
答案 0 :(得分:2)
我找到了这个惊人的例子,它回答了最初问题的第一点。第2点和第3点都没有任何答案。
#include <iostream>
#include <vector>
#include <chrono>
std::vector<double> f_val(std::size_t i, std::size_t n) {
auto v = std::vector<double>( n );
for (std::size_t k = 0; k < v.size(); ++k) {
v[k] = static_cast<double>(k + i);
}
return v;
}
void f_ref(std::size_t i, std::vector<double>& v) {
for (std::size_t k = 0; k < v.size(); ++k) {
v[k] = static_cast<double>(k + i);
}
}
int main (int argc, char const *argv[]) {
const auto n = std::size_t{10};
const auto nb_loops = std::size_t{300000000};
// Begin: Zone 1
{
auto v = std::vector<double>( n, 0.0 );
auto start_time = std::chrono::high_resolution_clock::now();
for (std::size_t i = 0; i < nb_loops; ++i) {
auto w = f_val(i, n);
for (std::size_t k = 0; k < v.size(); ++k) {
v[k] += w[k];
}
}
auto end_time = std::chrono::high_resolution_clock::now();
auto time = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time).count();
std::cout << time << std::endl;
std::cout << v[0] << " " << v[n - 1] << std::endl;
}
// End: Zone 1
{
auto v = std::vector<double>( n, 0.0 );
auto w = std::vector<double>( n );
auto start_time = std::chrono::high_resolution_clock::now();
for (std::size_t i = 0; i < nb_loops; ++i) {
f_ref(i, w);
for (std::size_t k = 0; k < v.size(); ++k) {
v[k] += w[k];
}
}
auto end_time = std::chrono::high_resolution_clock::now();
auto time = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time).count();
std::cout << time << std::endl;
std::cout << v[0] << " " << v[n - 1] << std::endl;
}
return 0;
}
在f_val的for循环中没有发生单个内存分配。这只发生在Clang(Gcc和icpc都失败了)和构建一个稍微复杂的例子时,优化没有完成。