c++ - C++ OpenMP 代码中的内存泄漏

标签 c++ memory openmp memory-leaks

我写了一个 c++ openmp 代码,它在并行区域中有一个动态分配的内存私有(private)变量,该区域处于 while 循环中。动态分配的内存在每个循环的并行区域结束时被释放。在每次分配和解除分配之后,我通过 linux 机器上的/proc/self/stat 文件监视内存。我发现驻留集大小的内存较少。为什么会这样?代码类似于 -

float *dynm;
while(condition)
{
    pragma omp parallel shared(list of variables) private(dynm)
    {
        read_values_from_/proc/self/stat_print_rss;
        dynm = new float[size]; 
        read_values_from_/proc/self/stat_print_rss;
        pragma omp for schedule(static, chunk) nowait
                for(counter)
        {
            do_operation;
        }
        delete []dynm;
        read_values_from_/proc/self/stat_print_rss;
    }
}

最佳答案

测量 RSS 并不是一种非常准确的内存泄漏搜索方法,因为它的计算方式非常复杂。有一些特殊的内存调试器,如 valgrind 或内置于 glibc 中的调试器,可以告诉您内存是否泄漏。您还必须了解 glibc 使用两种完全不同的机制来动态分配内存。

对于大型分配,它使用 mmap(2) 系统调用执行私有(private)匿名内存映射。此方法只能分配大小为系统页面大小(在大多数现代体系结构上为 4 KiB)倍数的 block ,因此不适用于小型分配。当浪费太多内存时,它甚至不适合更大的分配,例如如果您想分配 17 KiB 的 block ,则必须分配 20 KiB(4 KiB 的 5 倍),并且会浪费 15% 的内存。

对于较小的分配,使用系统提供的堆。有一种叫做系统中断的东西,它是进程的数据段结束的地方。它可以通过 brk(2) 系统调用向上移动以分配更多内存,向下移动以释放它。由于每个进程只有一个堆区域,操作系统将其视为一个 block ,因此 glibc 中内置了一个特殊的堆管理器,可以进一步将该 block segmentation 为更小的分配。

C++ new 运算符从 glibc 调用 malloc(3) 来执行内存分配。 malloc(3) 根据要分配的内存块的大小调用上述两种内存分配机制之一。 C++ delete 运算符从 glibc 调用 free(3),它是 malloc(3) 的释放拷贝。内存块被释放后会发生什么很大程度上取决于它最初是如何分配的。

使用 mmap(2) 机制分配的内存通过使用 munmap(2) 取消映射来释放。这将从进程的虚拟地址空间中删除内存映射,并释放用于支持分配的物理内存页。

对于在堆中分配的内存,事情要复杂得多,并且在很大程度上取决于用于管理它的算法。如果被释放的 block 不位于堆的末尾,而是位于其他地方,则堆大小不能减少,因为在高端内存地址上还有其他分配。这只是所谓的堆碎片表现出来的多种形式之一。未看到已用内存减少的另一个可能原因是堆管理器可能决定不向后移动中断的位置以预期 future 可能的分配并且调用 brk(2) 是一项昂贵的操作.

关于c++ - C++ OpenMP 代码中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12512262/

相关文章:

c++ - 使用 crypto++ 库进行 RAW RSA 签名验证

c++ - 这是 C++ 中的不合格查找吗?

c - 使用结构池正确处理内存

c - OpenMP : Parallel QuickSort

c++ - 如何在 C++ 中删除换行符

c++ - SFML C++ 绘制形状 vector

perl - 在 Perl 中初始化对象

C++ 指针和删除

c++ - 中值滤波器 OpenMP 优化

c++ - 待定:parallel_for 中的局部和全局结果