tracemalloc.start() 必须在程序最顶部(import之后、业务代码之前)调用,否则无法捕获启动前的内存分配;它只跟踪启用后的申请,不回溯,且需配合take_snapshot()、filter_traces()和compare_to('lineno')精准定位内存热点。

tracemalloc.start() 必须在程序早期调用
如果等内存已经分配完才启动 tracemalloc.start(),就捕获不到前面的分配记录。它只跟踪启动之后的内存申请,不回溯。常见错误是放在 main 函数末尾、或只在出问题后才加——这时候 trace 已经空了。
实操建议:
- 在脚本最顶部(
import之后、任何业务代码之前)调用tracemalloc.start() - 若用在 Web 服务(如 Flask/FastAPI),应在应用初始化阶段、路由注册前启用
- 可传参数限制追踪深度,例如
tracemalloc.start(25)表示最多记录 25 层调用栈,默认是 1
get_traced_memory() 和 take_snapshot() 的分工要分清
tracemalloc.get_traced_memory() 只返回当前总分配量和峰值,不含行号;真正能定位到哪行代码分配内存的,是 take_snapshot() + compare_to()。
实操建议:
- 想查“谁在持续吃内存”,先
snap1 = tracemalloc.take_snapshot(),过几秒再snap2 = tracemalloc.take_snapshot(),然后snap2.compare_to(snap1, 'lineno') -
'lineno'是关键排序维度,换成'filename'或'traceback'会改变聚合粒度 - 注意
compare_to()默认只显示差异 top 10,加参数limit=30才能看到更多
过滤无关路径避免干扰结果
默认快照包含标准库、虚拟环境路径里的分配(比如 /venv/lib/.../json/decoder.py),容易掩盖你自己的代码。不过滤的话,top 结果里全是第三方包。
实操建议:
- 用
filter_traces()剔除系统路径:snap = snap.filter_traces(( tracemalloc.Filter(False, '<frozen importlib._bootstrap>'), tracemalloc.Filter(False, '/venv/'), tracemalloc.Filter(True, 'my_module.py'), # 只保留自己的文件 ))</frozen> - 更稳妥的是在
start()时直接过滤:tracemalloc.start(10, traceback_limit=20)配合后续 filter - Windows 路径分隔符要用双反斜杠或原始字符串,否则正则匹配失败
别依赖 get_objects() 查 Python 对象引用
tracemalloc 跟踪的是 C 层 malloc 分配,不是 Python 对象引用计数。它看不到 list 里存了多少个 int,也识别不出循环引用。想查对象生命周期,得用 gc.get_objects() 配合 objgraph。
实操建议:
- 看到某行
data = [0] * 1000000占大量内存,tracemalloc能准确定位这一行;但若怀疑是某个闭包长期持有了不该持有的大对象,它帮不上忙 - 高内存增长但
tracemalloc显示“无明显热点”?大概率是对象未释放(比如缓存没清理、信号没断开),这时该切到gc和weakref排查
实际调试时,最常被忽略的是 snapshot 的时机和过滤粒度——不是 trace 不准,而是没让它聚焦在你要看的地方。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











