只能在CUDA中使用new运算符分配有限的内存

时间:2014-11-10 08:01:48

标签: c++ memory-management cuda

我写了一个这样的cuda内核

__global__ void mykernel(int size; int * h){

double *x[size];
for(int i = 0; i < size; i++){
  x[i] = new double[2];
}
h[0] = 20;
}

void main(){
  int size = 2.5 * 100000 // or 10,000
  int *h = new int[size];
  int *u;
  size_t sizee = size * sizeof(int);
  cudaMalloc(&u, sizee);
  mykernel<<<size, 1>>>(size, u);
  cudaMemcpy(&h, &u, sizee, cudaMemcpyDeviceToHost);
  cout << h[0];
}

我在内核中也有其他一些代码,但我已将其评论出来了。它上面的代码也分配了更多的内存。

现在当我运行size = 2.5 * 10 ^ 5时,我得到h [0]值为0;

当我使用size = 100 * 100运行时,我得到h [0]值为20;

所以我猜我的内核崩溃了,因为我的内存不足。我正在使用特斯拉卡C2075,它有2GB的内存!我甚至通过关闭xserver来尝试这个。我正在做的工作甚至不是100mb的数据。

如何为每个块分配更多内存?

1 个答案:

答案 0 :(得分:1)

  

现在当我运行size = 2.5 * 10 ^ 5时,我得到h [0]值为0;

     

当我使用size = 100 * 100运行时,我得到h [0]值为20;

在内核启动中,您还使用了此size变量:

mykernel<<<size, 1>>>(size, u);
           ^^^^

在cc2.0设备(Tesla C2075)上,1D情况下的此特定参数限制为65535.因此2.5 * 10 ^ 5超过65535,但100 * 100不会。因此,如果指定size为100 * 100,则内核可能正在运行,但如果指定size为2.5 * 10 ^ 5,则可能无法运行。

正如已经向您建议的那样,proper cuda error checking应该将此错误指向您,并且通常可能会导致您需要在SO上提出更少的问题,以及在SO上发布更高质量的问题。充分利用CUDA运行时的能力,让您知道出错的时间和出错的时间。然后你不会陷入困境,认为你有内存分配问题,实际上你可能有内核启动配置问题。

  

如何为每个块分配更多内存?

虽然这可能不是您的主要问题(如上所述),但内核中newmalloc仅限于设备堆的大小。一旦用尽,进一步调用newmalloc将返回空指针。如果你仍然使用这个空指针,你的内核代码将开始执行未指定的行为,并且可能会崩溃。

使用newmalloc时,尤其是当您遇到问题时,检查空返回值是一种很好的做法。这适用于主机(至少为malloc)和设备代码。

设备堆的大小一开始就很小(8MB),但可以修改。

参考the documentation

  

设备内存堆具有固定大小,必须在将任何使用malloc()或free()的程序加载到上下文之前指定。如果任何程序使用malloc()而未显式指定堆大小,则分配默认堆8兆字节。

     

以下API函数获取并设置堆大小:

     

•cudaDeviceGetLimit(size_t * size,cudaLimitMallocHeapSize)

     

•cudaDeviceSetLimit(cudaLimitMallocHeapSize,size_t size)

     

授予的堆大小至少为size个字节。 cuCtxGetLimit()和cudaDeviceGetLimit()返回当前请求的堆大小。