我编写了一个c ++ openmp代码,它在并行区域中有一个动态分配的内存私有变量,该区域在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;
}
}
答案 0 :(得分:5)
测量RSS不是一种非常准确的搜索内存泄漏的方法,因为它的计算方式非常复杂。有一些特殊的内存调试器,如valgrind
或内置于glibc
的调试器可以告诉你内存是否泄漏。您还必须了解glibc
使用两种完全不同的机制来动态分配内存。
对于大型分配,它使用mmap(2)
系统调用执行私有匿名内存映射。此方法只能分配大小为系统页面大小的倍数的块(在大多数现代体系结构上为4 KiB),因此不适合小分配。当浪费太多内存时,它甚至不适合更大的分配,例如,如果你想分配一个17 KiB的块,则必须分配20 KiB(5倍4 KiB),并且15%的内存将被浪费。
对于较小的分配,使用系统提供的堆。有一种叫做系统中断的东西,它是进程数据段结束的地方。它可以通过brk(2)
系统调用来移动以分配更多内存并向下移动以释放它。由于每个进程只有一个堆区域,并且操作系统将其视为单个块,因此glibc
内置了一个特殊的堆管理器,可以进一步将该块细分为更小的分配。
C ++ new
运算符从malloc(3)
调用glibc
来执行内存分配。 malloc(3)
根据要分配的存储块的大小调用上述两种存储器分配机制之一。 C ++ delete
运算符从free(3)
调用glibc
,malloc(3)
是mmap(2)
的释放对应项。内存块被解除分配后会发生什么,取决于它首先被分配的方式。
使用munmap(2)
机制分配的内存通过使用brk(2)
取消分配来解除分配。这将从进程的虚拟地址空间中删除内存映射,并释放用于支持分配的物理内存页。
对于在堆中分配的内存而言,事情变得更加复杂,并且更大程度上取决于用于管理它的算法。如果被释放的块不是位于堆的末尾,而是位于其他位置,那么堆大小不能减少,因为在高端内存地址上有其他分配。这只是所谓的堆碎片表现形式的众多形式之一。另一个不能看到已用内存减少的可能原因是堆管理器可能会决定不要在预期可能的未来分配时移回中断的位置,并且调用{{1}}是一项昂贵的操作。