如何让CuPy在变量超出作用域后彻底释放全部GPU内存?
彻底释放CuPy占用GPU内存的解决方案
问题场景
运行显存密集型CUDA C++模型前,用CuPy完成GPU预处理,转CPU后需要完全清空CuPy占用的所有GPU内存,但即使手动删除变量+调用free_all_blocks(),仍有内存残留,复杂场景下残留量可达数十GB,无法满足后续模型的显存需求(当前单卡仅余500MB空闲)。
有效解决方法
1. 全面清理CuPy内存池与CUDA缓存
除了默认内存池,还要清理pinned内存池及CUDA runtime级别的缓存,适合简单场景:
import cupy as cp def run(): X = cp.random.rand(10000000,300) y = cp.random.randn(300) out = X.dot(y) out_hst = cp.asnumpy(out) # 清理所有CuPy内存池 del X, y, out cp._default_memory_pool.free_all_blocks() cp._default_pinned_memory_pool.free_all_blocks() # 同步设备并触发CUDA缓存清理(CUDA 11.2+适用) cp.cuda.Device().synchronize() cp.cuda.runtime.mallocAsync(0) return out_hst
说明:CuPy的内存池分为普通和pinned两种,同时CUDA runtime会保留部分设备缓存,mallocAsync(0)会强制触发缓存回收。
2. 子进程隔离预处理(最彻底方案)
利用子进程退出时操作系统自动回收所有资源的特性,彻底清除包括cublas临时内存在内的所有GPU占用,适合复杂场景:
修改主脚本testcupy.py:
import numpy as np from multiprocessing import Process, Queue def preprocess(q): import cupy as cp X = cp.random.rand(10000000,300) y = cp.random.randn(300) out = X.dot(y) out_hst = cp.asnumpy(out) q.put(out_hst) if __name__ == "__main__": result_queue = Queue() proc = Process(target=preprocess, args=(result_queue,)) proc.start() out = result_queue.get() proc.join() # 子进程已结束,所有GPU内存完全释放 print("预处理完成,GPU内存已清空") input()
说明:子进程运行预处理任务,结束后操作系统会回收其占用的所有GPU资源,无需手动跟踪清理变量或内存池,彻底解决残留问题。
3. 验证内存释放状态
可以通过以下代码确认GPU内存是否完全释放:
import cupy as cp used_gb = cp.cuda.Device().mem_info[0] / (1024 ** 3) print(f"当前已用GPU内存: {used_gb:.2f} GB")
或者直接在终端执行nvidia-smi查看显存占用。
为什么之前的方法不彻底
- CuPy内存池默认会保留部分小内存块作为缓存,仅调用
free_all_blocks()无法清除CUDA runtime级别的设备缓存。 - 复杂场景中,cublas等底层库的临时内存不受CuPy内存池管理,手动删除变量无法回收这部分内存,子进程隔离是唯一彻底的解决方式。
内容的提问来源于stack exchange,提问作者dcgt1
相关产品推荐
相关产品推荐

