查看: 84|回复: 0

内存泄漏完整解析|PyTorch 大模型推理服务线上排障实战指南

[复制链接]

3075

主题

0

回帖

9264

积分

超级版主

积分
9264
发表于 2026-8-28 13:00:52 | 显示全部楼层 |阅读模式
导语

      很多 AI 开发者遇到线上诡异现象:推理服务刚启动运行流畅,随着运行时间拉长,进程内存、GPU 显存持续缓慢上涨,没有明确报错,过几小时或数天后被系统 OOM 杀掉重启。这极有可能就是内存泄漏(Memory Leak)。内存泄漏属于慢性故障,单元测试、短时压测很难复现,只有长时间运行才会暴露。本文通俗讲解内存泄漏底层原理,区分内存泄漏与 OOM 内存溢出,对比 C/C++ 手动管理内存与 Python 垃圾回收机制,梳理 AI 大模型 PyTorch 推理、RAG 项目高频泄漏场景,讲解监控排查工具与工程预防手段。

一、什么是内存泄漏

通俗租房类比:程序向操作系统申请内存就像租房子。正常用完之后归还房屋。内存泄漏就是租了房子,用完之后不归还,钥匙还攥在自己手里,操作系统无法回收再分配。 单次泄漏影响很小,不断重复执行就会大量内存被白白占用。
内存泄漏(Memory Leak):程序申请内存存放临时数据,业务逻辑已经不再使用这块数据,但由于引用没有释放,操作系统、垃圾回收器无法回收该内存,内存被持续占用。泄漏会不断累积,系统可用内存越来越少。
当物理内存耗尽,操作系统会把内存数据交换到速度极慢的磁盘交换分区,程序响应速度断崖式下跌;内存耗尽之后操作系统直接 OOM 杀死进程,服务崩溃。
⚠️重点区分:内存泄漏 vs OOM 内存溢出| 项目 | 内存泄漏 Memory Leak | 内存溢出 OOM Out‑Of‑Memory ||---|---|---|| 本质 | 不再使用的内存无法回收,持续堆积 | 申请内存时没有剩余可用空间 || 表现 | 内存随运行时间单调缓慢上涨,初期功能正常 | 瞬间内存耗尽,进程直接被杀 || 时间特征 | 慢性温水煮青蛙,长时间运行才爆发 | 流量高峰 / 大请求瞬间触发 || 因果关系 | 内存泄漏不断累积,最终会引发 OOM;但 OOM 不一定来自泄漏,大流量正常业务消耗也会直接 OOM |
两类语言的泄漏成因

  • C/C++ 手动内存管理:程序员malloc/new申请内存,忘记调用free/delete释放;异常提前 return 跳过释放代码,直接产生泄漏。完全依靠开发者手工管理内存生命周期。
  • Python、Java、JavaScript 带垃圾回收 GC垃圾回收 GC 规则:对象没有任何外部强引用,才会被回收释放内存
GC 不会自动 “清理你还拿着引用的对象”。即使业务已经不再使用该对象,如果全局集合、缓存、闭包、异步任务仍然持有强引用,GC 判定对象还在被使用,就不会回收,这就是 GC 语言里最常见的泄漏根源 ——意外强引用滞留
还有一类叫资源泄漏:文件句柄、数据库连接、网络流、CUDA 资源缓冲区,使用完毕没有关闭释放,缓冲区内存持续占用,也属于广义内存泄漏。
二、AI 大模型项目高频内存泄漏场景(PyTorch/Python)

AI 推理、RAG、LoRA 微调项目,Python+PyTorch 环境泄漏非常隐蔽,常见场景:
  • 全局 / 静态集合无限追加数据全局字典、list 作为缓存,不断存入张量、文档、向量对象,没有过期淘汰、LRU 清理机制,对象永久被强引用,GC 无法回收。
  1. # 危险示例:全局缓存无淘汰
  2. global_cache = {}
  3. def handle_query(req_id, tensor_data):
  4.     global_cache[req_id] = tensor_data   # 不断累积,永不清理
复制代码
  • PyTorch 张量残留引用推理忘记包裹with torch.no_grad(),计算图钩子、梯度信息残留;张量存入全局容器;detach()之后没有转为普通数值,仍然持有计算图引用,GPU 显存无法释放CSDN博...。
  • LoRA 适配器重复加载不卸载循环加载多个 LoRA 适配器,只加载不执行unload_adapter(),适配器权重、缓存持续驻留显存。
  • 异步任务、协程残留FastAPI/asyncio 任务异常退出,协程没有正确 await,任务对象、内部数据持续被引用驻留内存CSDN博...。
  • 资源未关闭文件句柄、数据库连接、向量库连接,异常分支没有执行 close;文件流缓冲区内存持续占用。
  • 第三方库 C 扩展泄漏Python 只是上层封装,底层 C/C++ 实现模块发生泄漏,Python GC 感知不到,tracemalloc只能看到 Python 层,C 侧堆内存泄漏需要memray工具观测GitHub。
三、怎么排查内存泄漏

核心判断特征:业务流量没有上涨,进程 RSS 物理内存仍然持续单调上涨,重启之后恢复正常,运行越久内存越高,大概率内存泄漏。
1、系统层面简易观测

Linux:top、htop,观察进程 RSS 内存变化;GPU:nvidia‑smi‑l观测显存变化;K8s 环境:监控容器 RSS 指标,配置 OOM 事件告警。
注意:短时压测看不出泄漏,泄漏需要长时间持续运行复现。
2、Python 专业分析工具

  • tracemalloc(Python 内置):追踪 Python 层内存分配,对比两次快照,定位哪一行代码分配大量内存Python
  1. import tracemalloc
  2. tracemalloc.start(25)
  3. # 执行业务逻辑
  4. snapshot = tracemalloc.take_snapshot()
  5. top_stats = snapshot.statistics('lineno')
  6. for stat in top_stats[:10]:
  7.     print(stat)
复制代码
  • memray:可以同时观测 Python 与 C 扩展分配,适合排查 PyTorch 底层 C 侧泄漏,支持生成火焰图。
  • objgraph:查看对象引用链,找出到底是谁还持有对象的强引用CSDN博...。
排查思路:采集程序刚启动快照,长时间运行业务后再采集快照,对比两次快照新增对象与内存增量,定位泄漏代码行。
四、工程预防内存泄漏最佳实践

1、谨慎使用全局容器做缓存

  • 全局字典不要无限追加;缓存务必增加淘汰策略:LRU、设置 maxsize、TTL 过期;
  • functools.lru_cache装饰器必须设置maxsize上限,禁止无限缓存。
2、PyTorch 推理规范

  • 推理逻辑务必包裹with torch.no_grad(),关闭梯度计算图;
  • 张量不要直接存入全局容器;detach 之后尽量转成普通 Python 数值;
  • LoRA 适配器用完及时 unload;空闲时可执行torch.cuda.empty_cache()(只释放无引用缓存);
  • 多 worker 部署注意避免模型重复加载。
3、资源遵循 “谁打开,谁关闭”

优先使用上下文管理器with语法,异常也会自动释放资源;数据库、文件、网络连接不要裸写 open 不关闭。
4、异步协程任务管理

asyncio 任务做好生命周期管控,异常场景也要保证任务完成,避免僵尸协程持有对象引用。
5、测试阶段增加长时间稳定性压测

普通单元测试时间太短,无法暴露泄漏;需要做几小时以上长时长稳定性压测,观测内存曲线。
6、线上监控告警

监控进程 RSS 内存、GPU 显存;设置内存水位告警;记录 OOM 事件,便于事后复盘。
注意:不要完全指望 GC 自动解决一切,GC 只能回收没有任何强引用的对象。
五、新手高频认知误区澄清

误区 1:有垃圾回收 GC,就不会发生内存泄漏

纠正:GC 只管回收没有引用的对象。只要意外保留强引用,GC 无能为力,Python/Java 都会出现内存泄漏。
误区 2:内存缓慢上涨一定就是内存泄漏

纠正:框架、PyTorch 会做内存池缓存,内存上涨但稳定不再增长属于正常缓存;持续单调无限上涨才是泄漏。
误区 3:调用torch.cuda.empty_cache()就可以根治显存泄漏

纠正:empty_cache 只能释放没有引用的缓存;如果对象还被强引用持有,调用该函数完全无效,根源要解决引用滞留问题。
误区 4:短时单元测试可以复现内存泄漏

纠正:泄漏大多需要长时间循环执行,短时测试很难暴露。
误区 5:OOM 就等于内存泄漏

纠正:大请求、大批次业务正常消耗内存也会 OOM,OOM 是结果,泄漏只是其中一类诱因。
六、本期全文总结

1 内存泄漏:不再使用的内存因为引用没有释放,持续累积;区分 OOM 内存溢出,泄漏是慢性过程,最终可能触发 OOM。2 C/C++ 是手工忘记释放;Python/Java GC 语言泄漏大多来自意外强引用:全局缓存、闭包、异步任务、张量残留引用;广义泄漏包含文件、数据库句柄资源泄漏。3 AI PyTorch 项目高频坑:全局无上限缓存、张量计算图残留、LoRA 适配器只加载不卸载、异步僵尸任务、底层 C 扩展泄漏。4 排查:观察 RSS 内存是否随运行时间单调上涨;使用 tracemalloc、memray 做快照对比,定位分配位置。5 预防:缓存加淘汰策略,推理开启 no_grad,资源优先上下文管理器,长时长稳定性压测,线上配置内存监控告警。6 GC 不是万能的,开发者依然要管好对象生命周期,不能全部交给垃圾回收。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|天翼网

相关侵权、举报、投诉及建议等,请发 E-mail:2026@typc.net

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.|晋ICP备2026008270号-1|晋公网安备14010602111293号

QQ客服返回顶部