CUDA对象使用问题:操作设备变量后回拷主机报非法地址错误
解决CUDA中__device__指针访问非法地址的问题
看起来你遇到的问题核心是设备端全局指针d_a没有被正确初始化指向有效的设备内存,加上printf触发了对无效地址的访问,才导致了cudaErrorIllegalAddress错误。咱们一步步拆解问题,再给出修复后的代码:
问题根源分析
你的代码里存在几个关键疏漏:
- 只在主机端创建了
A对象,但没有在设备端分配对应的内存空间 __device__ A *d_a是设备端的全局指针,主机端不能直接给它赋值,必须通过CUDA API来设置它指向设备上的有效内存- 当核函数里执行
printf("%d\n", d_a->s)时,d_a还没指向有效的设备内存,自然会触发非法地址访问;而注释掉printf后,核函数没有实际访问无效内存,所以表面上看起来“正常”,但其实设备端指针还是无效的
修复后的完整代码
#include <stdio.h> class A { public: int s; }; // 设备端全局指针 __device__ A *d_a; __global__ void MethodA() { // 现在可以安全访问d_a指向的设备内存了 printf("%d\n", d_a->s); } int main() { // 1. 主机端创建并初始化对象 A *a = new A(); a->s = 10; // 给成员变量赋值 // 2. 在设备端分配A对象的内存 A *d_temp; cudaMalloc(&d_temp, sizeof(A)); // 3. 将主机端的A对象拷贝到设备内存 cudaMemcpy(d_temp, a, sizeof(A), cudaMemcpyHostToDevice); // 4. 将设备端内存地址赋值给__device__指针d_a cudaMemcpyToSymbol(d_a, &d_temp, sizeof(A*)); // 5. 启动核函数 MethodA<<<1, 1>>>(); // 6. 同步设备并检查错误(一定要加,方便调试) cudaDeviceSynchronize(); cudaError_t err = cudaGetLastError(); if (err != cudaSuccess) { printf("CUDA error: %s\n", cudaGetErrorString(err)); } // 7. 测试:将设备端对象拷贝回主机验证 A *host_back = new A(); cudaMemcpy(host_back, d_temp, sizeof(A), cudaMemcpyDeviceToHost); printf("Host received: %d\n", host_back->s); // 8. 释放内存 delete a; delete host_back; cudaFree(d_temp); return 0; }
关键修复点解释
- 设备内存分配:用
cudaMalloc在设备上为A对象申请内存,这是设备端数据的实际存储位置 - 设置__device__指针:通过
cudaMemcpyToSymbol将设备内存地址赋值给全局指针d_a,这是主机端操作设备全局变量的标准方式,不能直接用d_a = d_temp(主机无法直接访问设备全局变量的地址空间) - 错误检查:添加
cudaDeviceSynchronize和cudaGetLastError可以帮你快速定位核函数执行时的错误,避免隐性问题 - 内存释放:记得释放主机和设备上的所有内存,避免内存泄漏
现在运行这段代码,printf就能正常输出设备端对象的s值,拷贝回主机也不会报错了。
内容的提问来源于stack exchange,提问作者Tóth Bence
相关产品推荐
相关产品推荐

