
python如何查看内存泄漏
程序运行一段时间后内存持续增长,即使相关任务已经结束,进程占用的内存也没有明显回落,这种情况可能与内存泄漏有关。
通过进程监控观察内存趋势
可以使用 psutil 定期记录进程内存:
import os
import time
import psutil
process = psutil.Process(os.getpid())
for _ in range(10):
memory_mb = process.memory_info().rss / 1024 / 1024
print(f'当前内存:{memory_mb:.2f} MB')
time.sleep(1)
如果程序执行相同任务时,RSS 内存持续上升且长时间不回落,可以结合对象分析工具进一步定位。
当怀疑某类对象没有被释放时,可以比较不同时间点的对象数量和引用关系。
使用 tracemalloc 定位内存分配
tracemalloc 可以记录 Python 对象的内存分配位置:
import tracemalloc
tracemalloc.start()
# 执行可能产生内存泄漏的代码
run_task()
snapshot = tracemalloc.take_snapshot()
for item in snapshot.statistics('lineno')[:10]:
print(item)
输出结果会显示占用内存较多的代码行。也可以保存两个快照进行对比:
before = tracemalloc.take_snapshot()
run_task()
after = tracemalloc.take_snapshot()
for item in after.compare_to(before, 'lineno')[:10]:
print(item)
需要注意,tracemalloc 主要追踪 Python 层的内存分配,无法完整覆盖部分 C 扩展模块申请的内存。
有些对象并非真正泄漏,而是仍然被全局变量、缓存、闭包、容器或循环引用持有。检查对象引用关系有助于确认具体原因。
结合 gc 和 objgraph 分析引用链
可以使用 gc 获取当前对象数量,并检查无法回收的对象:
import gc
gc.collect()
print('对象数量:', len(gc.get_objects()))
print('无法回收对象:', gc.garbage)
安装 objgraph 后,可以查看增长较快的对象类型:
pip install objgraph
import objgraph
objgraph.show_growth(limit=10)
如果发现某类对象持续增加,可以进一步使用 objgraph.show_backrefs() 查看哪些对象持有它们的引用。
线上服务通常需要低侵入、可持续采样的分析方式,直接暂停程序进行调试可能影响业务响应。
根据场景选择 memory_profiler、memray 或 heapy
memory_profiler 适合查看函数或代码行的内存变化:
pip install memory_profiler
python -m memory_profiler app.py
在目标函数上添加 @profile 即可获得逐行内存使用情况。
memray 适合分析 Python 代码和 C 扩展产生的内存分配:
pip install memray
memray run app.py
memray flamegraph memray-*.bin
pympler 或 guppy3 适合检查对象数量、对象大小和堆内存状态。生产环境使用时,建议在测试环境复现问题,并控制采样时长与数据量。
删除变量只会减少一个引用,内存是否归还给操作系统还取决于对象引用数量、Python 垃圾回收机制以及内存分配器的行为。
区分对象释放和进程内存回收
可以用 sys.getrefcount() 检查对象引用数量,用 gc.collect() 主动触发垃圾回收:
import gc
data = [bytearray(1024 * 1024) for _ in range(20)]
del data
gc.collect()
即使对象已经释放,Python 内存分配器也可能暂时保留已申请的内存,以便后续复用,因此操作系统监控到的 RSS 不一定立即下降。判断是否存在泄漏时,应重点观察相同任务下对象数量和内存占用是否持续增长,而不是只看单次 del 后的结果。