tracemalloc.start() 必须在程序最早期调用,即脚本最顶部、早于任何模块导入和全局初始化;默认仅存1帧调用栈,建议设为25以追踪业务函数层级,并需用filter_traces()聚焦自身代码路径,且take_snapshot()应手动置于关键逻辑边界点以定位内存突增。

tracemalloc.start() 必须在程序最早期调用
如果你在导入大量模块、创建全局对象或启动线程之后才调用 tracemalloc.start(),那之前所有内存分配都不会被记录——tracemalloc 只能捕获它启用之后的分配点。常见错误是把它放在主逻辑里、甚至放在某个函数内部,结果发现 get_traced_memory() 有增长,但 get_top() 却几乎为空。
正确做法是:在脚本最顶部(if __name__ == "__main__": 之前)、且早于任何第三方库初始化的位置调用:
import tracemalloc <p>tracemalloc.start(25) # 25 表示最大回溯帧数,别设太小</p><h1>后续再 import numpy, pandas, flask... 等等
注意:tracemalloc.start() 默认只保存 1 帧调用栈,这意味着你只能看到 malloc 的直接调用者(比如 list.append),看不到它被谁调用。设成 25 或更高才能追踪到业务函数层级。
立即学习“Python免费学习笔记(深入)”;
如何让 get_top() 显示真正的业务代码路径
tracemalloc.get_top() 返回的堆栈默认包含 C 扩展和标准库内部调用(如 PyObject_Malloc、PyList_New),这些对定位 Python 层问题帮助很小。你需要过滤掉无关帧,并聚焦在你自己的包或模块上。
推荐做法是结合 filter_traces() 和自定义规则:
- 用
tracemalloc.Filter(True, <your_package_path>)只保留你关心的路径 - 避免用
Filter(False, "lib/python")这类模糊排除——容易漏掉关键中间层 - 如果项目用 Poetry 或 venv,
your_package_path通常是os.path.abspath("src")或项目根目录
示例:
import tracemalloc
import os
<p>tracemalloc.start(25)</p><h1>... 运行可疑代码 ...</h1><p>snapshot = tracemalloc.take_snapshot()</p><h1>只保留 src/ 下的调用帧</h1><p>my_filter = tracemalloc.Filter(True, os.path.abspath("src"))
filtered = snapshot.filter_traces([my_filter])
top_stats = filtered.statistics("traceback")
for stat in top_stats[:5]:
print(stat)为什么 take_snapshot() 要在关键节点手动触发
tracemalloc 不会自动采样;它只是持续记录分配事件。如果你只在程序结尾调一次 take_snapshot(),拿到的是整个生命周期的累积数据,无法区分“哪段逻辑导致了突增”。真实场景中,内存问题往往出现在某次循环、某个 API 请求或某个数据加载阶段。
应把 take_snapshot() 放在可对比的边界点:
- 请求处理前 + 处理后(Web 框架中可在中间件前后)
- 大循环迭代前 + 迭代 N 次后(配合
gc.collect()减少干扰) - 调用可疑函数
func()前后各一次,再用compare_to()计算差值
注意:不要在热循环内高频调用 take_snapshot()——它本身有开销,可能掩盖真实问题或拖慢执行。
tracemalloc 无法追踪的内存类型有哪些
它只跟踪 CPython 内存分配器(PyMem_Malloc 等)的调用,因此以下情况不会出现在 trace 中:
- C 扩展自己调用
malloc()(如某些 NumPy 底层操作、Cython 模块) - mmap 分配的大块内存(例如某些数据库驱动、memoryview 背后的 buffer)
- Python 对象引用计数变化导致的间接内存压力(如循环引用未及时回收)
- 多线程中非主线程的分配——除非你在每个线程里单独
start()(不推荐,开销大)
如果 get_traced_memory() 显示增长很小,但 RSS 却飙升严重,大概率踩中了上面某条。这时候得换工具:用 psutil.Process().memory_info().rss 监控实际内存,再配合 objgraph 或 gc.get_objects() 查对象堆积。


















