在这里就不得不提出cudaMalloc函数的使用cudaMalloc((void** devPtr,size_t size),
为何内存申请用void**而不用void*?
答:
首先要明确cudaMalloc函数在执行完成后,向这个地址写入了一个地址值(此地址值是GPU显存里的)。
int* ptr = nullptr;
size_t bytes = sizeof(int) * 10;
cudaError_t cuda_error = cudaMalloc((void**)&d_indata,bytes);
注:
1)cudaMalloc的函数模型为cudaError_t cudaMalloc (void **devPtr, size_t size ); 其cudaMalloc函数的作用是在GPU上分配内存(分配线性大小的内存),devPtr是一个指针,什么样的指针呢,是一个指向已经分配好gpu内存的这么一个指针!(指针是指向数据的地址,指针即地址)。
也就是说,这个CPU上的指针变量devPtr所在的内存单元存储的是GPU所分配的显存首地址!
2)d_indata是一个指针,cudaMalloc函数结束后,该指针即d_indata就指向一个已经分配好的gpu内存空间。也就是指针就是地址,就是相当于在这个内存空间的门牌号码!
3)双重指针**,即指针的指针。第一重的指针pointer1指向一个内存空间space1(该空间存有东西或不存储东西为空),指针pointer1就是space1所在的内存空间的地址。第二重的指针pointer2指向另一个内存空间space2,该内存空间space2里面的放的内容就是第一重的指针pointer1,即放的内容就是地址编号。(也就是指针pointer1)
———————————————————分割线—————————————————————
int* ptr = nullptr; size_t bytes = sizeof(int) * 10; cudaError_t cuda_error = cudaMalloc((void**)&d_indata,bytes);
cudaError_t cudaMalloc (void **devPtr, size_t size );
dptr这个指针是存储在CPU的内存上,假设dptr= 0x001f,int** ddptr = &dptr,ddptr = 0x034f。
假设使用void*,那么就是直接传入的dptr。cudaMalloc函数在传入dptr时,是先进行将dptr复制给形参devPtr,即如下:
void* devptr = dptr;
完成一维指针变量dptr复制给形参devPtr后,然后再进行GPU内存分配,如下:
devptr = malloc(10);
void* devptr = dptr;这句话即void* devptr与dptr此时指向相同的内存空间,经过malloc函数就分配了10这个大小的内存空间。
GPU分配内存的首地址写入了devPtr内存单元。那么cudaMalloc执行完后,dptr的内存单元的数值没有改变(即指向的地址没有变),依旧为0x001f,而0x001f是在cpu上的内存地址,因此通过dptr是访问不到GPU分配的内存空间的。
使用void**就可以避免这个问题。传入的是指针dptr(int* dptr)的指针ddptr(int** ddptr),在cudaMalloc函数内部会执行,那么*ddptr就是一维指针dptr的值(地址编号)(如果再次解引用就是获取一维指针dptr所指向的内存空间中的内容),直接存储GPU分配内存的首地址:
int* dptr = nullptr; int** ddptr = &dptr; *ddptr = malloc(10);
注意:malloc函数的返回值类型是 void *,void 并不是说没有返回值或者返回空指针,而是返回的指针类型未知。
。所以在使用 malloc() 时通常需要进行强制类型转换,将 void 指针转换成我们希望的类型,例如:
char *ptr = (char *)malloc(10); // 分配10个字节的内存空间,用来存放字符
reference
cudaMalloc((void** devPtr,size_t size),内存申请用void**的原因总结 - 知乎