这类问题我又碰上了一次。自建 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 是否单调上涨,就能区分缓存池碎片和真正的泄漏。报错文案容易误导,真正的原因往往在相邻那一层的日志里。

作者 9823189