OpenMP 中的 C++ 动态内存分配速度较慢,即使对于非并行代码段也是如此

Posted

技术标签:

【中文标题】OpenMP 中的 C++ 动态内存分配速度较慢,即使对于非并行代码段也是如此【英文标题】:C++ dynamic memory allocation is slower in OpenMP, even for non-parallel sections of code 【发布时间】:2015-08-25 14:17:35 【问题描述】:

我在使用 OpenMP 时遇到了一个相当令人沮丧的问题:似乎如果 OpenMP 在代码中的某处以并行模式使用(用于多个线程),那么动态内存分配/解除分配会变得更慢,即使在非代码的并行部分。这是一个示例程序(只是一个说明):

int main()

    #pragma omp parallel
    
        // Just to get OpenMP going
    

    double wtime0, wtime;
    wtime0 = omp_get_wtime();

    double **stuff;
    const int N = 1000000;

    stuff = new double*[N];
    for (int i=0; i < N; i++) stuff[i] = new double;
    for (int i=0; i < N; i++) *(stuff[i]) = sqrt(i);
    for (int i=0; i < N; i++) delete[] stuff[i];
    delete[] stuff;

    wtime = omp_get_wtime() - wtime0;
    cout << "Total CPU time: " << wtime << endl;

当我在笔记本电脑(即 Intel Core 2 Duo)上使用一个线程运行此代码时,我得到的 CPU 时间为 0.093。另一方面,如果我用两个线程运行它,CPU 时间会增加到 0.13。指针分配越多,差异就越严重。在上面的代码中,如果我用一个简单的数组替换“stuff”,例如

    double stuff2[N];
    for (int i=0; i < N; i++) stuff2[i] = sqrt(i);

那么没有差异。有人可以告诉我为什么在分配/取消分配指针时存在这个问题,即使它不是并行完成的?这是一个问题的原因是因为在我正在使用的实际代码中,动态内存分配是必不可少的。有些部分可以通过并行运行来加速,但是(使用两个线程对一个线程)这远远超过了内存分配/解除分配速度大大减慢的事实,即使在非并行部分中也是如此。如果具有丰富 OpenMP 经验的人能告诉我如何解决这个问题,我将不胜感激。 (最坏的情况,我可以只使用 MPI,但如果这可以在 OpenMP 中解决,我会很高兴。)

提前感谢您的帮助。

【问题讨论】:

内存分配通常非常昂贵。在并行环境中,情况会变得更糟,因为它们可能会在相同的内部数据结构上争夺相同的锁。如果您对性能很认真,请将分配移到更高的级别或完全摆脱它们。很多时候,没有免费的午餐,而且你的蛋糕也很难吃。 【参考方案1】:

是的,这是可以想象的。一般来说,应该避免在多线程环境中进行简单的动态分配,因为那里只有一个锁。 MT-aware 分配器提供了更好的性能,在分配繁重的场景中应该是首选。 这就是为什么我在这里总是对只使用向量或字符串或共享指针作为类成员而不让用户指定分配策略的代码感到不满的原因。

【讨论】:

有趣...我没有听说过 MT 感知分配器(我只是一个不起眼的物理学家,不是计算机科学家)。是否有您可能推荐的预制分配器?我遇到了 jemalloc,但不知道那是否是更好的之一。另外,如果您知道讨论此问题的特别好的论文/文章,我也将不胜感激。谢谢。 广泛使用的解决方案是来自 Google 的 tcmalloc。我自己更喜欢 g++ 的 mt_allocator - 它是一个符合 C++ 的分配器。我不知道有任何文章,但我敢肯定,如果你只是在你最喜欢的搜索引擎中输入 tcmalloc,你会看到很多。 我会尝试 TBB malloc、TCMalloc 和/或 JEMalloc。 PTMalloc 很好,但不是为这种用途而设计的。 您无需重新编译即可试验 TBB malloc。见threadingbuildingblocks.org/docs/help/tbb_userguide/… 用 tcmalloc 编译完全解决了这个问题。我仍然不完全理解它是如何修复它的,但我很高兴知道它已经修复并继续前进。感谢您让我知道这件事!

以上是关于OpenMP 中的 C++ 动态内存分配速度较慢,即使对于非并行代码段也是如此的主要内容,如果未能解决你的问题,请参考以下文章

OpenMP 并行代码运行速度较慢

Java堆与栈

java中堆和栈的区别

java的内存管理机制

在 C++ 中的 2D 动态内存分配数组中释放分配的内存

什么是 C++ 中的动态内存分配?