本文目录导读:

对于Python内存泄漏测试,pytest-memprof 是一个可选方案,但我更推荐组合使用 pytest + tracemalloc 或 memory_profiler,不过让我先分析一下 pytest-memprof 的适用性。
pytest-memprof 的优缺点
优点
- 专门为 pytest 设计
- 装饰器语法简洁
- 可以基于使用量设定阈值
缺点
- 项目维护不活跃(最后更新较久)
- 功能相对基础
- 不如 tracemalloc 精细
推荐方案
方案1:pytest + tracemalloc(最推荐)
Python 3.4+ 内置,无需额外安装:
import tracemalloc
def test_memory_leak():
tracemalloc.start()
# 记录初始快照
snapshot1 = tracemalloc.take_snapshot()
# 执行可能泄漏的操作
for _ in range(1000):
data = create_large_object()
# 忘记释放...
# 记录结束快照
snapshot2 = tracemalloc.take_snapshot()
# 比较差异
stats = snapshot2.compare_to(snapshot1, 'lineno')
# 断言内存增长在合理范围内
total_growth = sum(stat.size_diff for stat in stats)
assert total_growth < 10 * 1024 * 1024 # 小于10MB
方案2:pytest + memory_profiler
from memory_profiler import profile
@profile
def test_function():
# 测试代码
result = []
for i in range(10000):
result.append('x' * 1000)
return result
def test_memory():
# 使用 mprof 命令行工具
# mprof run pytest test.py
# mprof plot
pass
方案3:自定义 pytest fixture + tracemalloc
import pytest
import tracemalloc
@pytest.fixture
def memory_check():
tracemalloc.start()
yield
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
# 报告内存使用
print(f"Current: {current / 1024 / 1024:.2f} MB")
print(f"Peak: {peak / 1024 / 1024:.2f} MB")
def test_with_leak(memory_check):
leaker = LeakyClass()
for _ in range(1000):
leaker.leak()
实际测试框架示例
完整的测试框架:
# conftest.py
import pytest
import tracemalloc
import gc
@pytest.fixture(autouse=True)
def memory_leak_check():
"""自动检查每个测试的内存泄漏"""
tracemalloc.start()
gc.collect() # 清理垃圾
snapshot_before = tracemalloc.take_snapshot()
yield
gc.collect() # 强制垃圾回收
snapshot_after = tracemalloc.take_snapshot()
# 过滤掉内部调用
stats = snapshot_after.compare_to(snapshot_before, 'lineno')
stats = [s for s in stats if not s.traceback[0].filename.startswith('<')]
significant_leaks = [s for s in stats if s.size_diff > 1024] # > 1KB
if significant_leaks:
print("\n内存泄漏检测结果:")
for stat in significant_leaks[:5]: # 显示前5个
print(stat)
# test_memory.py
def test_no_leak():
"""正常测试"""
data = [1, 2, 3]
assert sum(data) == 6
def test_potential_leak():
"""可能泄漏的测试"""
class Leak:
def __init__(self):
self.data = [0] * 1000000
# 会创建大量对象但不释放
for _ in range(100):
l = Leak()
专业工具
对于生产环境,推荐:
-
pytest-leaks:专门的内存泄漏测试插件
pip install pytest-leaks pytest --leaks test.py
-
objgraph:查看对象引用图
import objgraph def test_reference_cycles(): # 检测循环引用 objgraph.show_most_common_types(limit=10)
不建议单独使用 pytest-memprof,因为:
- 功能局限且维护少
- 不如内置 tracemalloc 灵活
推荐组合:
- 日常测试:pytest + tracemalloc(内置)
- 详细分析:pytest + memory_profiler
- CI/CD集成:pytest-leaks 或自定义 fixture
选择最适合你项目的工具组合即可。