C ++堆内存性能提高

| 我正在编写一个需要大量堆内存的函数。是否可以告诉编译器那些数据将在特定的“ 0”循环内被频繁访问,从而提高性能(通过编译选项或类似选项)? 我不能使用堆栈的原因是我需要存储的元素数量很大,如果尝试这样做会出现分段错误。 目前该代码正在运行,但我认为它可能会更快。 更新: 我正在做这样的事情
vector< set<uint> > vec(node_vec.size());
for(uint i = 0; i < node_vec.size(); i++)
  for(uint j = i+1; j < node_vec.size(); j++)
    // some computation, basic math, store the result in variable x
      if( x > threshold ) {
         vec[i].insert(j);
         vec[j].insert(i);
      }
一些细节: -我使用了hash_set,没有什么改进,除了hash_set并非在我拥有的用于模拟目的的所有机器上都可用 -我尝试使用数组在堆栈上分配vec,但是正如我所说,如果元素数量太大,我可能会遇到分段错误 如果node_vec.size()等于k,其中k约为几千,则我期望vec比node_vec大4到5倍。考虑到我必须多次运行的事实,在这个数量级上,代码看起来很慢。当然,我正在使用多线程来并行化这些调用,但是我无法让函数本身运行的速度比我现在看到的快得多。 例如,是否可以在高速缓存中分配vec以进行快速数据检索或类似的操作?     
已邀请:
更新
vector< set<uint> > vec(node_vec.size());
for(uint i = 0; i < node_vec.size(); i++)
  for(uint j = i+1; j < node_vec.size(); j++)
    // some computation, basic math, store the result in variable x
      if( x > threshold ) {
         vec[i].insert(j);
         vec[j].insert(i);
      }
这仍然显示不了多少,因为我们不知道条件
x > threshold
会多久出现一次。如果
x > threshold
经常是正确的,那么
std::set
可能是瓶颈,因为它必须为插入的每个
uint
进行动态内存分配。 同样,我们也不知道“某种计算”实际上是什么意思。如果它做了很多事情,或者做错了方法,那可能就是瓶颈。 而且我们不知道您需要如何获取结果。 无论如何,预感:
    vector<pair<int, int> > vec1;
    vector<pair<int, int> > vec2;

    for (uint i = 0; i < node_vec.size(); i++)
    {
        for (uint j = i+1; j < node_vec.size(); j++)
        {
            // some computation, basic math, store the result in variable x
            if (x > threshold)
            {
                vec1.push_back(make_pair(i, j));
                vec2.push_back(make_pair(j, i));
            }
        }
    }
如果您可以在该表格中使用结果,那么您就完成了。否则,您可以进行一些后处理。只是不要再将其复制到5英镑了(显然)。尝试坚持
std::vector<POD>
。例如。您可以像这样在向量中建立索引:
    // ...
    vector<int> index1 = build_index(node_vec.size(), vec1);
    vector<int> index2 = build_index(node_vec.size(), vec2);
    // ...
}    

vector<int> build_index(size_t count, vector<pair<int, int> > const& vec)
{
    vector<int> index(count, -1);

    size_t i = vec.size();
    do
    {
        i--;
        assert(vec[i].first >= 0);
        assert(vec[i].first < count);
        index[vec[i].first] = i;
    }
    while (i != 0);

    return index;
}
ps:我几乎可以确定您的循环不受内存限制。但是不能确定...如果您未向我们显示的“节点”确实很大,那么它可能仍然会很大。 原始答案: 没有简单的“ 11”类解决方案。 您可以做一些事情。 确保编译器可以“查看”在关键循环内调用的每个函数的实现。编译器能够“看到”实现的必要条件取决于编译器。但是,有一种方法可以确保:在循环之前在同一个转换单元中定义所有相关函数,并将它们声明为
inline
。 这也意味着您绝对不应在这些关键循环中调用\“ external \”函数。通过“外部”功能,我的意思是诸如系统调用,运行时库的东西或在DLL / SO中实现的东西。也不要调用虚拟函数,也不要使用函数指针。并且或者当然不分配或释放内存(在关键循环内)。 确保使用最佳算法。如果算法的复杂度比必要的高,那么线性优化就没有意义了。 使用尽可能小的类型。例如。如果
signed char
可以胜任,请不要使用
int
。我通常不建议这样做,但是在处理大量内存时,它可以大大提高性能。特别是在非常紧密的循环中。 如果您只是复制或填充内存,请使用
memcpy
memset
。如果块大于50到100个字节,则禁用这两个函数的内部版本。 确保以缓存友好的方式访问数据。最佳的是“流式传输”,即以递增或递减的地址访问存储器。您可以一次“跳过”一些字节,但不要跳得太远。最糟糕的是随机访问一大块内存。例如。如果必须处理二维矩阵(如位图图像),其中p [0]至p [1]是\“向右\”(x + 1)的步长,请确保内部循环将x和外部增量y。如果您这样做,则相反的性能会差很多。 如果指针是无别名的,则可以告诉编译器(如何完成取决于编译器)。如果您不知道无别名的含义,我建议您搜索网络和编译器的文档,因为超出了说明的范围。 如果适用,请使用内部SIMD指令。 如果您知道在不久的将来需要哪些存储位置,请使用显式的预取指令。     
我正在编写一个需要大量堆内存的函数...将在特定的for循环中频繁访问 这不是您真正可以在编译器级别进行优化的东西。我认为您担心的是,您有很多可能是“过时的”(调出)的内存,但是在特定的时间点上,您将需要遍历所有内存,可能需要多次,并且您不需要希望将内存页面分页到磁盘。 您将需要研究特定于平台的策略以提高性能。使用
mlockall
VirtualLock
可以将页面保留在内存中,但是您实际上不需要这样做。但是,请确保您知道将应用程序的内存页锁定到RAM的含义是什么。您正在占用其他进程的内存。 您可能还想研究碎片少的堆(但是,它可能根本与该问题无关),并且此页面描述了关于“ 0”循环的高速缓存行。 后面的页面是有关内存访问的CPU工作原理(您通常不必关心的细节)的细节。   示例1:内存访问和性能   与Loop 1相比,您希望Loop 2运行多少速度?
int[] arr = new int[64 * 1024 * 1024];

// Loop 1
for (int i = 0; i < arr.Length; i++) arr[i] *= 3;

// Loop 2
for (int i = 0; i < arr.Length; i += 16) arr[i] *= 3;
     第一个循环将数组中的每个值乘以3,第二个循环仅每16个相乘。第二个循环仅完成第一个循环工作的6%,但是在现代机器上,两个for循环大约需要相同的时间:在我的机器上分别为80毫秒和78毫秒。     
使用编译器选项无法做到这一点。根据您的用法(插入,随机访问,删除,排序等),您可能会得到一个更合适的容器。     
编译器已经可以看到循环中经常访问数据。     
假设您在执行循环之前仅从堆中分配了一次数据,请注意@lvella,即内存就是内存,并且如果频繁访问它,则应该在执行期间有效地对其进行缓存。     

要回复问题请先登录注册