除全局内存不足外,CUDA出现"out of memory"错误的其他原因?
CUDA循环调用后
cudaCreateTextureObject报"out of memory"但全局内存充足的问题排查与解决 问题概述
在Python/MATLAB环境中循环调用CUDA代码约34K次后,cudaCreateTextureObject触发"out of memory"错误,但设备全局内存仍有大量空闲(11GB/12GB)。每次循环输入完全相同,监测显示全局内存仅占用1GB且无增长;调用cudaDeviceReset()可规避错误但会大幅增加耗时,推测存在非全局内存资源泄漏。
环境信息:CUDA V12.3.103、RTX 4070,CUDA代码通过MEX/Cython封装供上层调用,可通过TIGRE库运行示例代码复现问题。
原因分析
cudaMemGetInfo仅统计全局内存的使用情况,无法覆盖CUDA运行时的资源对象占用:
- 每次调用
CreateTexture都会创建新的纹理对象(cudaTextureObject_t),但未对应调用cudaDestroyTextureObject释放 - 纹理对象属于CUDA的运行时资源,不属于全局内存范畴,这类资源累积到一定数量后会触发OOM错误,与全局内存剩余量无关
解决方案
核心是在每次使用完纹理对象后显式释放资源,同时同步处理关联的cudaArray(若开启allocate参数)。
1. 添加资源销毁函数
补充与CreateTexture对应的销毁逻辑,确保资源被正确回收:
void DestroyTexture(const GpuIds& gpuids, cudaArray** d_cuArrTex, cudaTextureObject_t* texImage, bool allocate) { const unsigned int num_devices = gpuids.GetLength(); for (unsigned int dev = 0; dev < num_devices; dev++) { cudaSetDevice(gpuids[dev]); // 先销毁纹理对象(依赖cudaArray资源) if (texImage[dev] != 0) { cudaDestroyTextureObject(texImage[dev]); texImage[dev] = 0; // 重置标记避免重复销毁 } // 若allocate为true,销毁对应的cudaArray if (allocate && d_cuArrTex[dev] != nullptr) { cudaFreeArray(d_cuArrTex[dev]); d_cuArrTex[dev] = nullptr; } cudaDeviceSynchronize(); cudaCheckErrors("DestroyTexture fail"); } }
2. 调整循环调用逻辑
在Python/MATLAB的循环迭代中,每次调用CreateTexture完成计算后,立即调用DestroyTexture释放资源:
- 确保销毁操作在对应GPU设备上下文执行(
cudaSetDevice) - 等待异步流操作完成后再执行销毁(通过
cudaDeviceSynchronize或流同步函数)
3. 原CreateTexture函数的补充检查
- 若
allocate参数为true,每次循环都会创建新的cudaArray,必须在销毁阶段释放,否则会导致全局内存泄漏 - 确保纹理对象和
cudaArray的销毁顺序:先销毁纹理对象,再销毁cudaArray,避免资源依赖错误
验证步骤
- 修改TIGRE库中
Atb函数的实现,在计算逻辑结束后调用DestroyTexture释放资源 - 运行复现代码,观察是否还会触发OOM错误
- 可通过打印纹理对象的创建/销毁计数,验证资源是否被正确回收
内容的提问来源于stack exchange,提问作者Ander Biguri
相关产品推荐
相关产品推荐

