Python中如何检测Web应用是否存在内存泄漏
现在情况是这样的,今天一起来发现 aws 上 supervisor tornado 进程的内存占用好高,以前一般是一个进程 60M 左右 , 今天基本都是 400M 以上,甚至有 900M 的,有没有办法知道怎么内存泄漏了吗
Python中如何检测Web应用是否存在内存泄漏
6 回复
python 有 gc 模块
检测Python Web应用内存泄漏,核心是监控进程内存使用并分析对象引用。推荐用 tracemalloc 和 objgraph 来定位问题。
先装个包:
pip install objgraph
下面是个Flask应用的例子,演示怎么用:
import tracemalloc
import objgraph
from flask import Flask, jsonify
import gc
app = Flask(__name__)
# 启动内存跟踪
tracemalloc.start()
# 模拟一个可能泄漏的数据结构
leaky_data = []
@app.route('/leak')
def leaky_endpoint():
""" 这个端点每次调用都会泄漏数据 """
# 模拟泄漏:将大量数据添加到全局列表,且不释放
data = [i for i in range(10000)]
leaky_data.append(data)
return jsonify({"message": "Data added", "current_leak_size": len(leaky_data)})
@app.route('/memory')
def memory_status():
""" 查看当前内存快照和对象增长情况 """
# 获取当前内存快照
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')[:10] # 按行号统计前10
result = {
"top_memory_allocations": [
f"{stat.count} blocks, {stat.size / 1024:.2f} KB: {stat.traceback.format()[-1]}"
for stat in top_stats
],
"leaky_data_length": len(leaky_data),
"tracked_object_types": objgraph.most_common_types(limit=5)
}
return jsonify(result)
@app.route('/objgraph')
def show_growth():
""" 显示特定类型对象的增长情况(需要提前在另一个端点调用后对比) """
# 这里只是示例,实际使用需要在两个时间点分别调用objgraph.show_growth()
gc.collect() # 强制垃圾回收,让结果更准确
growth = objgraph.show_growth(limit=10)
return jsonify({"object_growth": growth})
if __name__ == '__main__':
app.run(debug=True)
跑起来之后:
- 多访问几次
/leak端点,模拟泄漏。 - 访问
/memory看内存分配情况和leaky_data列表的增长。 - 访问
/objgraph查看对象增长情况(实际调试时,更建议在代码里直接调用objgraph.show_growth()并打印到日志)。
关键点:
tracemalloc跟踪的是Python内存分配器层面的分配,能告诉你哪行代码分配的内存最多。objgraph擅长分析对象引用关系。真正要定位泄漏源,可以在怀疑泄漏的代码前后,分别调用objgraph.show_growth(),看看哪些对象的数量只增不减。- 对于Web应用,持续监控
/memory这类端点,如果内存使用量在请求处理后只升不降,基本就是泄漏了。
一句话建议:用 tracemalloc 找分配点,用 objgraph 查引用链。
查看一下有没有全局变量没删除吧?
检查一下是否存在相互引用导致 Handler 没有被回收. 因为 Tornado 会为每一个请求构建新的 Handler 处理请求. 如果当前 Handler 的 self 传递给其他对象保存, 同时又把该对应绑定到了 self 上就会产生内存泄露.
PS. 如果没有引起 OOM 就没啥大问题.
有一个叫 meliae 的库你可以看一眼


