如何使用Cuda避免segfault上的内存泄漏

How to avoid memory leak on segfault with Cuda

本文关键字:内存 泄漏 segfault 何使用 Cuda 避免      更新时间:2023-10-16

我在集成分支上使用cuda设备,在完成工作时仍有一些segfault。

每次崩溃后,我的内存消耗都会增加500 Mo(使用free -mhtop和另一个,但我记不起名字了)。这个内存从来没有释放过,所以在这台有4Go RAM的计算机上,所以我必须在一些崩溃后重新启动,否则内存交换真的很慢(就像往常一样,当内存交换发生时)。

我知道最好的答案是:"修复你的segfault!!"但我想了解为什么会发生这种行为,以及我如何防止它。

我读到CUDA内存应该由操作系统在segfault上发布,但看起来并没有。

当我尝试调试我的程序时,我注意到如果我修复了segfault,内存就可以正常释放了,但如果我也注释了cuda发布行:cudaFreeHost(buf)(修复了sedfault),我仍然存在内存泄漏。

我的内存被分配为固定页面:cudaHostAlloc(&ret, n*sizeof(my_struct), cudaHostAllocPortable)

我想确保使用unique_ptr调用"free"代码,但它不能解决segfault的问题。

我研究了CUDA的持久模式:http://docs.nvidia.com/deploy/driver-persistence/index.html但它在我的电脑上是禁用的(我用nvidia-smi检查了它)。

我试图重置cuda设备:nvidia-smi -r,但它说我的计算机不支持它。

问题是:

  • 我们如何要求程序(或操作系统)在程序结束时释放这些资源
  • 如果我们不能,是否存在在崩溃后恢复这些资源的命令

版本

  • CUDA 6.0.1

  • gcc 4.9.2

  • 驱动程序版本:340.65

  • 卡:GeForce 610M

更新

下面是重现该问题的示例代码。有了评论行,我每次运行泄漏10 Mo。

#include <cuda.h>
#include <cuda_runtime.h>
int main() {
    int *ret;
    cudaHostAlloc(&ret, 10000000 * sizeof(*ret), cudaHostAllocPortable);
    //cudaFreeHost(ret);
    return 0;
}

更新2

             total       used       free     shared    buffers     cached
Mem:       3830056    1487156    2342900      66336     142840     527088
-/+ buffers/cache:     817228    3012828
Swap:      7811068          0    7811068
1Erreur de segmentation
2Erreur de segmentation
3Erreur de segmentation
4Erreur de segmentation
5Erreur de segmentation
6Erreur de segmentation
7Erreur de segmentation
8Erreur de segmentation
9Erreur de segmentation
10Erreur de segmentation
11Erreur de segmentation
12Erreur de segmentation
13Erreur de segmentation
14Erreur de segmentation
15Erreur de segmentation
16Erreur de segmentation
17Erreur de segmentation
18Erreur de segmentation
19Erreur de segmentation
20Erreur de segmentation
             total       used       free     shared    buffers     cached
Mem:       3830056    1766580    2063476      64152     142860     531032
-/+ buffers/cache:    1092688    2737368
Swap:      7811068          0    7811068

我为您的repro case构建了一个稍微修改过的版本:

#include <cuda.h>
#include <cuda_runtime.h>
#include <signal.h>
int main() {
    int *ret;
    const size_t sz = 1 << 30;
    cudaHostAlloc(&ret, sz * sizeof(*ret), cudaHostAllocPortable);
    raise(SIGSEGV);
    return 0;
}

在我的系统上,它应该分配8Gb的固定便携式内存,并引发一个segfault,这会产生异常退出和核心转储。我在一台16Gb机器上运行了这个程序,该机器带有352.39驱动程序和CUDA 6运行时,处于shell循环中,根据您的分析,这应该会在两三次运行内导致泄漏和缓存抖动:

$ free; for i in {1..20}; do echo -n $i; ./a.out; done; free
             total       used       free     shared    buffers     cached
Mem:      16308996    3509924   12799072          0     303588    2313332
-/+ buffers/cache:     893004   15415992
Swap:      8257532          0    8257532
1Segmentation fault (core dumped)
2Segmentation fault (core dumped)
3Segmentation fault (core dumped)
4Segmentation fault (core dumped)
5Segmentation fault (core dumped)
6Segmentation fault (core dumped)
7Segmentation fault (core dumped)
8Segmentation fault (core dumped)
9Segmentation fault (core dumped)
10Segmentation fault (core dumped)
11Segmentation fault (core dumped)
12Segmentation fault (core dumped)
13Segmentation fault (core dumped)
14Segmentation fault (core dumped)
15Segmentation fault (core dumped)
16Segmentation fault (core dumped)
17Segmentation fault (core dumped)
18Segmentation fault (core dumped)
19Segmentation fault (core dumped)
20Segmentation fault (core dumped)
             total       used       free     shared    buffers     cached
Mem:      16308996    3510740   12798256          0     303588    2313272
-/+ buffers/cache:     893880   15415116
Swap:      8257532          0    8257532

然而,您可以看到,在分配160Gb的固定内存并且从不调用内存版本API或允许代码遵循正常代码路径退出后,可用内存仅减少0.006%。未发生内存泄漏或可用资源发生净更改。

CUDA驱动程序和运行时将在退出时释放主机和GPU资源,无论是正常还是异常,无论是否显式调用无内存API。我不能告诉你你的代码或系统有什么问题,但CUDA运行时或驱动程序在应用程序退出时缺乏主机资源释放很可能不是根本原因。

我鼓励您修改我的代码以适应机器上物理内存的大小(使用一半的物理内存),并像我在循环中所做的那样运行它,在循环之前或之后直接报告内存。我非常怀疑你是否会看到与我在回复中发布的内容不同的内容。如果你这样做,我强烈建议你更新最新版本的驱动程序。