PyTorch默认caching_allocator缓存释放的显存块而不归还CUDA驱动,导致nvidia-smi显存居高不下;需用PYTORCH_CUDA_ALLOC_CONF切换分配器或禁用缓存,torch.cuda.empty_cache()仅清PyTorch缓存池中无引用的块。

PyTorch默认显存分配器为什么吃得多又不释放?
PyTorch默认用的是caching_allocator,它会把释放掉的显存块缓存起来供后续复用,而不是还给CUDA驱动。这导致nvidia-smi看到的显存占用长期居高不下,哪怕你已经del tensor、torch.cuda.empty_cache(),甚至退出with torch.no_grad():作用域——缓存池还在。
真正释放显存给系统,得靠环境变量强制切换分配器或关闭缓存行为:
-
CUDA_VISIBLE_DEVICES=0:先确认只暴露目标卡,避免跨卡隐式分配 -
PYTORCH_CUDA_ALLOC_CONF=max_split_size_mb:128:限制最大内存块切分粒度,防止碎片化后无法复用(值太小会增加分配开销) - 更激进的做法是禁用缓存:
PYTORCH_CUDA_ALLOC_CONF=allocator:cudaMallocAsync(仅CUDA 11.8+,需驱动≥525),它用异步分配器,释放即归还,nvidia-smi读数更“诚实”
torch.cuda.empty_cache()到底有没有用?
有用,但只清空PyTorch缓存池里“未被任何tensor引用”的显存块,不碰CUDA驱动层。如果模型还在运行、梯度没清、requires_grad=True的中间变量仍存活,empty_cache()基本没效果。
实操建议:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
- 在
torch.no_grad()上下文里推理时调用,比训练中调用更有效 - 配合
del显式删除大tensor,再gc.collect(),最后torch.cuda.empty_cache() - 别在循环里频繁调用——它本身有开销,且不能解决持续增长的缓存池问题
训练中显存暴涨却找不到泄漏点?检查这几个地方
显存不降往往不是分配器问题,而是Python对象生命周期失控:
- 日志或可视化里意外保留了
loss、output等GPU tensor(比如写进list.append(loss)) -
model.train()模式下BatchNorm和Dropout会缓存中间状态;若误在验证阶段没切到.eval(),这些状态持续累积 - 使用
torch.utils.checkpoint时,若use_reentrant=False未设好,可能引发梯度图重复驻留 - Dataloader的
num_workers>0且pin_memory=True时,worker进程可能持有GPU张量副本(罕见,但多卡调试时出现过)
如何验证显存配置是否生效?
光看nvidia-smi不够,得交叉验证:
- 启动前加
echo $PYTORCH_CUDA_ALLOC_CONF确认环境变量已加载 - 代码开头打印
torch.cuda.memory_summary(),关注allocatedvsreserved两列——前者是PyTorch实际用掉的,后者是缓存池向驱动申请的总量;切换cudaMallocAsync后,这两者应趋近一致 - 用
torch.cuda.memory_allocated()在关键节点打点,比依赖nvidia-smi更准(后者含驱动开销、其他进程干扰)
注意cudaMallocAsync在某些旧版cuDNN或自定义CUDA扩展里可能触发兼容性报错,错误信息通常是CUDA driver version is insufficient for CUDA runtime version或invalid device pointer,此时退回max_split_size_mb微调更稳妥。

















