Python中如何检测Web应用是否存在内存泄漏

现在情况是这样的,今天一起来发现 aws 上 supervisor tornado 进程的内存占用好高,以前一般是一个进程 60M 左右 , 今天基本都是 400M 以上,甚至有 900M 的,有没有办法知道怎么内存泄漏了吗


Python中如何检测Web应用是否存在内存泄漏
6 回复

python 有 gc 模块


检测Python Web应用内存泄漏,核心是监控进程内存使用并分析对象引用。推荐用 tracemallocobjgraph 来定位问题。

先装个包:

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)

跑起来之后:

  1. 多访问几次 /leak 端点,模拟泄漏。
  2. 访问 /memory 看内存分配情况和 leaky_data 列表的增长。
  3. 访问 /objgraph 查看对象增长情况(实际调试时,更建议在代码里直接调用 objgraph.show_growth() 并打印到日志)。

关键点:

  • tracemalloc 跟踪的是Python内存分配器层面的分配,能告诉你哪行代码分配的内存最多。
  • objgraph 擅长分析对象引用关系。真正要定位泄漏源,可以在怀疑泄漏的代码前后,分别调用 objgraph.show_growth(),看看哪些对象的数量只增不减。
  • 对于Web应用,持续监控 /memory 这类端点,如果内存使用量在请求处理后只升不降,基本就是泄漏了。

一句话建议:用 tracemalloc 找分配点,用 objgraph 查引用链。

查看一下有没有全局变量没删除吧?

我都怀疑是 AWS 的问题了

检查一下是否存在相互引用导致 Handler 没有被回收. 因为 Tornado 会为每一个请求构建新的 Handler 处理请求. 如果当前 Handler 的 self 传递给其他对象保存, 同时又把该对应绑定到了 self 上就会产生内存泄露.

PS. 如果没有引起 OOM 就没啥大问题.

有一个叫 meliae 的库你可以看一眼

回到顶部