如何释放函数封装返回的CUDA纹理对象占用的显存?
解决方案
问题的核心是:cudaDestroyTextureObject仅销毁纹理对象本身,但不会自动释放关联的cudaArray_t显存资源,必须显式调用cudaFreeArray才能释放这部分内存。要解决泄漏,需要修改函数设计,让调用者能获取并管理cudaArray_t的生命周期,具体步骤如下:
1. 定义资源结构体,统一管理关联资源
创建一个结构体来封装纹理对象和对应的cudaArray_t,确保两者能被一起销毁:
#include <cuda_runtime.h> #include "matrix.h" // Matlab mxArray相关头文件 typedef struct { cudaTextureObject_t texObj; cudaArray_t cudaArr; } TextureResource;
2. 修改创建函数,返回完整资源结构体
调整mxArrayToTexture函数,通过输出参数返回包含cudaArray_t的资源结构体,同时在出错时及时释放已分配的资源:
cudaError_t mxArrayToTexture(const mxArray* mxArr, TextureResource* outResource) { if (!mxArr || !outResource) return cudaErrorInvalidValue; // 初始化输出结构体 memset(outResource, 0, sizeof(TextureResource)); // 1. 从mxArray获取维度、数据类型等信息(原有逻辑保留) const int* dims = mxGetDimensions(mxArr); size_t width = dims[0]; size_t height = dims[1]; size_t depth = (mxGetNumberOfDimensions(mxArr) >=3 ) ? dims[2] : 1; size_t dataSize = mxGetNumberOfElements(mxArr) * mxGetElementSize(mxArr); // 2. 创建cudaArray_t(原有逻辑保留,增加错误处理) cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(8, 8, 8, 8, cudaChannelFormatKindUnsigned); // 示例,根据mxArray类型调整 cudaError_t err = cudaMallocArray(&outResource->cudaArr, &channelDesc, width, height, depth); if (err != cudaSuccess) return err; // 3. 拷贝数据到cudaArray(原有逻辑保留,增加错误回滚) err = cudaMemcpyToArray(outResource->cudaArr, 0, 0, mxGetData(mxArr), dataSize, cudaMemcpyHostToDevice); if (err != cudaSuccess) { cudaFreeArray(outResource->cudaArr); outResource->cudaArr = NULL; return err; } // 4. 创建纹理资源和对象(原有逻辑保留) cudaResourceDesc resDesc; memset(&resDesc, 0, sizeof(resDesc)); resDesc.resType = cudaResourceTypeArray; resDesc.res.array.array = outResource->cudaArr; cudaTextureDesc texDesc; memset(&texDesc, 0, sizeof(texDesc)); // 根据需求设置纹理属性:寻址模式、过滤模式、读写模式等 texDesc.addressMode[0] = cudaAddressModeClamp; texDesc.filterMode = cudaFilterModeLinear; texDesc.readMode = cudaReadModeElementType; err = cudaCreateTextureObject(&outResource->texObj, &resDesc, &texDesc, NULL); if (err != cudaSuccess) { cudaFreeArray(outResource->cudaArr); outResource->cudaArr = NULL; return err; } return cudaSuccess; }
3. 实现配套销毁函数,统一释放资源
编写一个销毁函数,确保同时销毁纹理对象和cudaArray_t,避免调用者遗漏:
void destroyTextureResource(TextureResource* resource) { if (!resource) return; // 先销毁纹理对象 if (resource->texObj != 0) { cudaDestroyTextureObject(resource->texObj); resource->texObj = 0; } // 再释放cudaArray显存 if (resource->cudaArr != NULL) { cudaFreeArray(resource->cudaArr); resource->cudaArr = NULL; } }
4. 使用示例
// 创建纹理资源 TextureResource texRes; cudaError_t err = mxArrayToTexture(yourMxArray, &texRes); if (err != cudaSuccess) { // 错误处理 } // 使用纹理对象texRes.texObj进行CUDA计算... // 销毁资源(必须调用此函数,而非单独调用cudaDestroyTextureObject) destroyTextureResource(&texRes);
关键说明
cudaArray_t是独立的显存分配资源,纹理对象对象只是对它的引用,销毁纹理对象不会自动释放cudaArray_t的内存。- 创建过程中任何步骤失败时,都要及时释放已分配的
cudaArray_t,避免中途泄漏。 - 必须通过统一的销毁函数管理资源,不要让调用者单独操作
cudaTextureObject_t和cudaArray_t,降低出错概率。
内容的提问来源于stack exchange,提问作者PBragg
相关产品推荐
相关产品推荐

