内存问题通常比 CPU 瓶颈更难排查——程序不报错,但内存持续增长,最终被系统 OOM Killer 杀掉。Python 给开发者提供了从“逐行分析”到“底层追踪”的完整内存分析工具链,其中memory_profiler和tracemalloc是最常用的两个。
memory_profiler:逐行看内存,粗暴直接
memory_profiler 是第三方库,它最核心的能力是:告诉你每一行代码执行后,内存占用量增加了多少。
安装
pip install memory-profiler
基本使用
在需要分析的函数上添加 @profile 装饰器,然后用 Python 执行脚本(注意:不能直接在 Jupyter 中用,需要将脚本保存为 .py 文件在终端运行):
# example.py
from memory_profiler import profile
@profile
def process_data():
data = [i for i in range(100000)] # 创建一个列表
squared = [x**2 for x in data] # 生成平方值
del data # 释放原列表
return squared
if __name__ == '__main__':
process_data()
终端运行:
python -m memory_profiler example.py
你会看到类似这样的输出:
Line # Mem usage Increment Line Contents
================================================
4 35.4 MiB 35.4 MiB @profile
5 def process_data():
6 38.4 MiB 3.0 MiB data = [i for i in range(100000)]
7 42.1 MiB 3.7 MiB squared = [x**2 for x in data]
8 38.3 MiB -3.8 MiB del data
9 38.3 MiB 0.0 MiB return squared
每一行的内存增/减一目了然,你马上就知道哪一步造成了内存飙升。
更强大的功能:mprof
memory_profiler 还附带命令行工具 mprof,可以按时间采样整个进程的内存使用并绘制图表,适合长时间运行的脚本:
mprof run python my_script.py
mprof plot
tracemalloc:追踪内存分配痕迹,适合排查泄漏
tracemalloc 是 Python 3.4 起内置的标准库模块,它不关心“每行涨了多少内存”,而是记录每一次内存分配发生在哪个文件、哪一行,帮你找到“谁分配了内存却迟迟不释放”。
基本用法:捕获快照,对比差异
import tracemalloc
tracemalloc.start() # 开始追踪
# ---- 模拟一段可能泄漏的操作 ----
data1 = [i for i in range(100000)]
snapshot1 = tracemalloc.take_snapshot() # 拍快照
del data1 # 释放
# ---- 再跑一段 ----
data2 = [i for i in range(200000)]
snapshot2 = tracemalloc.take_snapshot()
# 比较两个快照,找出多出来的内存分配
stats = snapshot2.compare_to(snapshot1, 'lineno')
for stat in stats[:5]:
print(stat)
输出示例:
<...>/example.py:6: size=800 KiB (+800 KiB), count=1 (+1), average=800 KiB
<...>/example.py:9: size=1.6 MiB (+1.6 MiB), count=1 (+1), average=1.6 MiB
这里清楚显示第 9 行分配了 1.6 MiB 内存,且是净增长(未被释放)。多次拍快照对比,就能精确定位长期不释放的内存分配点,也就是泄漏源。
显示前 N 个内存消耗大户
# 取当前快照按文件统计
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('filename')
for stat in top_stats[:5]:
print(stat)
实用分工建议
- 快速定位“胖函数”:用 memory_profiler 直接看到函数内哪几行最耗内存,适合代码重构优化。
- 追查隐藏泄漏:遇到“程序跑着跑着内存就满了”的情况,在上线前或测试环境中启用 tracemalloc,对比多个时间点的快照,找出那些只增不减的分配点。
- 注意性能影响:tracemalloc 启动后会额外记录每次分配,对性能有一定影响(但通常可接受),生产环境慎开;memory_profiler 的逐行装饰器也会拖慢执行,仅用于调试分析。
两者结合,基本覆盖了从“内存用多了”到“内存收不回来”的所有常见场景。