vscode运行python时显存未满却oom,主因是pytorch显存碎片化、vscode复用python进程未释放cuda上下文、dataloader多进程预占显存。需结合memory_summary诊断碎片、杀残留进程、设num_workers=0排查、合理使用empty_cache。

VSCode 运行 Python 时显存没满却报 OOM?先看 allocated 和 reserved 差多少
PyTorch 的 torch.cuda.memory_allocated() 返回当前被张量实际占用的显存,而 torch.cuda.memory_reserved() 返回缓存池里已预留但未分配给张量的显存。两者差值大(比如 allocated=12GB,reserved=28GB),基本就是碎片化在作祟——nvidia-smi 显示“占了 40GB”,但真正能用的连续块可能只剩几百 MB。
实操建议:
- 在训练循环前/后插入
print(torch.cuda.memory_summary()),重点看 “allocated”、“reserved”、“largest block” 三栏 - 如果 “largest block” 远小于 “reserved - allocated”,说明碎片严重,
torch.cuda.empty_cache()可能有救;但如果 “largest block” 接近 “allocated”,那大概率是 batch_size 或模型本身真超限 - 别只信 nvidia-smi:它显示的是进程总显存映射量,不反映 PyTorch 内部碎片状态
VSCode 调试/运行后显存不释放?检查 Python 进程是否真退出
VSCode 默认复用 Python 进程(尤其在调试或 Run Python File 时),即使脚本执行完,进程也可能挂着不动。这时你新跑一个脚本,它会继承旧进程的 CUDA 上下文和缓存池,显存自然“越积越多”。这不是 VSCode 插件占显存,而是它没杀干净进程。
实操建议:
- 每次运行前手动在终端执行
ps aux | grep python,确认无残留python train.py进程;若有,用kill -9 PID干掉 - VSCode 设置里关掉
python.terminal.executeInFileDir和python.debugging.useTerminal,改用内置调试器(更可控) - 在脚本末尾加
torch.cuda.empty_cache()+exit(0),强制清缓存并退出进程(注意:仅用于调试,别放正式训练循环里)
DataLoader 的 num_workers 导致显存悄悄翻倍?先设为 0 测试
num_workers > 0 会让每个 worker 子进程初始化自己的 CUDA 上下文,哪怕你没在 Dataset.__getitem__ 里碰 GPU,每个 worker 也会预占 500MB–1GB 显存。16 个 worker 就可能白占 8GB+,且这些显存无法被主进程的 empty_cache() 清理。
实操建议:
- 第一步永远是设
num_workers=0运行一次,如果 OOM 消失,问题就锁定在这里 - 必须用多进程时,禁用
pin_memory=True(除非你明确需要 host pinned memory 加速 transfer) - PyTorch ≥ 1.11 可加
worker_init_fn=lambda x: torch.cuda.set_per_process_memory_fraction(0.1),限制单 worker 最大显存使用比例 - 避免在
__getitem__中调用.cuda()或创建 tensor;所有 GPU 操作移到collate_fn或训练 step 内
频繁调用 empty_cache() 反而让碎片更糟?只在关键节点清一次
torch.cuda.empty_cache() 不是“清垃圾”,它是把缓存池里所有未被引用的块归还给 CUDA 驱动。但频繁调用会打乱分配器的块合并策略,反而加剧碎片。它对多卡默认只作用于当前 device,且在子进程里无效。
实操建议:
- 只在函数退出、大临时张量被
del后、且下一步要分配更大张量时调用一次,例如验证完 epoch 后 - 多卡训练需遍历设备:
for i in range(torch.cuda.device_count()): torch.cuda.set_device(i); torch.cuda.empty_cache() - 别在训练循环里每步都 call —— 它本身耗时毫秒级,且触发后 allocator 重建空闲链表,容易产生小碎片
- 真正治碎片得靠源头控制:固定 batch_size、避免中间张量大小剧烈波动、用梯度检查点减少激活值驻留
真实场景里,最常被忽略的是:VSCode 启动的 Python 进程没真正退出,DataLoader worker 预占显存又不释放,再加上训练循环里盲目调 empty_cache(),三者叠加,显存就“越跑越碎”。查问题得从进程生命周期、worker 行为、allocator 机制三层一起看,单点优化往往白忙。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











