这类问题我又碰上了一次。自建 embedding 服务用 torch 2.4 加 transformers 4.44,循环里每 100 条记录一次显存快照,跑 8 小时后 80GB 卡只剩 6GB,重启就恢复。服务是推理模式,试过 torch.cuda.empty_cache 只能回收一点,memory_allocated 一路在涨,压测 30 分钟也一样。
第一反应是「输出张量转 numpy 时没 detach,和 GPU 存储共享一块内存」,验证下来不成立。
排查方向其实有限,先把可能性排一排。统计用的中间 tensor 被塞进列表,一直持有前面所有 batch;前向没包在 no_grad 里,计算图跟着激活一起留在显存;每轮循环都新建一次 tokenizer,缓存对象越积越多。
动手时先看 allocated 与 reserved 的差值
python -c "import torch;print(round(torch.cuda.memory_allocated()/2**30,2), round(torch.cuda.memory_reserved()/2**30,2))"
然后确认当前是否处在梯度记录模式
python -c "import torch;print(torch.is_grad_enabled())"
转 numpy 前显式 detach 并移回 CPU
python -c "import torch;t=torch.randn(1024,device='cuda');print(t.detach().cpu().numpy().shape)"
压测半小时看显存曲线是否走平
nvidia-smi --query-gpu=memory.used --format=csv -l 10 -c 180
恢复的判定其实很直接。连续压测 30 分钟显存稳定在 24GB 上下不再上涨,allocated 与 reserved 的差值回到 1GB 以内。
这里还有个坑。显存阶梯上涨几乎都是对象没释放,先看 allocated 是否单调上涨,就能区分缓存池碎片和真正的泄漏。报错文案容易误导,真正的原因往往在相邻那一层的日志里。
