python如何查看内存泄漏

python如何查看内存泄漏

作者:William Gu发布时间:2026-08-14 21:59阅读时长:19 分钟阅读次数:9
常见问答
Q
怎样判断 Python 程序是否存在内存泄漏?

程序运行一段时间后内存持续增长,即使相关任务已经结束,进程占用的内存也没有明显回落,这种情况可能与内存泄漏有关。

A

通过进程监控观察内存趋势

可以使用 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 内存持续上升且长时间不回落,可以结合对象分析工具进一步定位。

Q
Python 中如何找出不断增加的对象?

当怀疑某类对象没有被释放时,可以比较不同时间点的对象数量和引用关系。

A

使用 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 扩展模块申请的内存。

Q
如何确认对象为什么没有被垃圾回收?

有些对象并非真正泄漏,而是仍然被全局变量、缓存、闭包、容器或循环引用持有。检查对象引用关系有助于确认具体原因。

A

结合 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() 查看哪些对象持有它们的引用。

Q
哪些工具适合分析线上 Python 服务的内存问题?

线上服务通常需要低侵入、可持续采样的分析方式,直接暂停程序进行调试可能影响业务响应。

A

根据场景选择 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

pymplerguppy3 适合检查对象数量、对象大小和堆内存状态。生产环境使用时,建议在测试环境复现问题,并控制采样时长与数据量。

Q
为什么执行 del 后进程内存没有下降?

删除变量只会减少一个引用,内存是否归还给操作系统还取决于对象引用数量、Python 垃圾回收机制以及内存分配器的行为。

A

区分对象释放和进程内存回收

可以用 sys.getrefcount() 检查对象引用数量,用 gc.collect() 主动触发垃圾回收:

import gc

data = [bytearray(1024 * 1024) for _ in range(20)]
del data
gc.collect()

即使对象已经释放,Python 内存分配器也可能暂时保留已申请的内存,以便后续复用,因此操作系统监控到的 RSS 不一定立即下降。判断是否存在泄漏时,应重点观察相同任务下对象数量和内存占用是否持续增长,而不是只看单次 del 后的结果。

* 文章含AI生成内容