objgraph比gc.get_objects()更适合定位内存泄漏,因其能生成引用图、回溯引用链、过滤类型,精准定位web中handler等对象被长期持有的根因。

Python Web 应用内存持续上涨,不是缓存增长的假象,大概率是对象被意外长期持有——objgraph 能直接看到谁在强引用目标对象,比猜更准。
为什么 objgraph 比 gc.get_objects() 更适合定位泄漏点
objgraph 不只列出对象数量,它能生成引用图、回溯引用链、过滤特定类型,对 Web 场景中“某个 Handler 实例一直不释放”这类问题特别有效。而 gc.get_objects() 返回的是全量对象快照,需手动遍历过滤,容易漏掉关键引用路径。
- Web 请求生命周期短,但 handler、request、response 对象若被全局监听器、日志缓冲区或未解绑回调持有着,就会滞留
-
objgraph.show_backrefs([obj])可以从疑似泄漏对象出发,一层层往上查“谁还拿着它” -
objgraph.show_growth()在请求前后调用,能快速识别新增最多、最可疑的类型(如Request、Response、自定义Task)
在 Sanic/FastAPI/Flask 中注入 objgraph 的最小可行方式
不要等服务崩了再查。在中间件里加几行,就能捕获真实运行时的引用状态:
- 安装:
pip install objgraph - 在请求入口处记录基线:
objgraph.show_growth(limit=10)(首次调用会清空内部计数器) - 在响应返回前抓差异:
objgraph.show_growth(limit=10),观察哪些类数量猛增 - 若发现某类(如
MyDataProcessor)持续不降,立即用objs = objgraph.by_type("MyDataProcessor")获取实例列表,选最新一个做回溯:objgraph.show_backrefs([objs[-1]], max_depth=5, filename="backref.png")
注意:生成 PNG 需要 graphviz,Linux/macOS 用 brew install graphviz 或 apt install graphviz;Windows 用户可改用 objgraph.show_backrefs(..., refcounts=True) 输出文本引用链。
常见误判和绕不开的坑
看到 show_backrefs 输出一堆框架内部引用,别急着修——很多是正常生命周期管理。重点看三类路径:
- 是否出现在
globals()或模块级字典里?例如:my_cache[request_id] = processor却从未清理 - 是否被
asyncio.Task或后台线程的局部变量间接持有?检查asyncio.create_task()后有没有await或task.cancel() - 是否因闭包捕获了大对象?比如在路由函数里定义 lambda 回调,而该 lambda 引用了整个
self或request - 避免在生产环境频繁调用
show_backrefs——它会暂停 GC 并深度遍历引用,可能拖慢接口。只在复现泄漏时临时启用
真正难处理的从来不是“找不到泄漏对象”,而是“找到后发现它被三个不同模块的弱引用+一个日志钩子+一个未 await 的协程共同持有”。这时候得逐个确认每个持有方的销毁契约是否被遵守,而不是指望单个工具一锤定音。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











