【发布时间】:2018-10-19 10:40:43
【问题描述】:
我有一个处理 xml 文档的烧瓶应用程序(烧瓶版本 1.0.2)。文档以 json 格式发布,如下所示:
import requests
import sys
import json
with open('big.xml', encoding="utf-8") as f:
xml_string = f.read()
print(sys.getsizeof(xml_string) // 1024 // 1024)
# 283
gid = "FOO"
json_data = json.dumps({"file_content": xml_string, "self_id": gid})
print(sys.getsizeof(json_data) // 1024 // 1024)
# 305
result_json = requests.post("http://my_server:8080/api", data=json_data, headers={"Content-Type": "application/json"})
如您所见,xml 文件可能非常大,在本示例中约为 300 MB。
为了简化,我的烧瓶应用程序如下所示:
from flask import Flask, request, jsonify
from memory_profiler import profile
app = Flask(__name__)
@app.route('/api', methods=['POST'])
@profile
def api():
input_data = request.get_json()
output_data = {"id": "FOO"}
response = jsonify(output_data)
return response
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080, debug=True)
在发布请求期间,flask 应用程序的内存使用量飙升至 ~2.8 GB。上面代码中的内存分析与这些数字相去甚远:
Line # Mem usage Increment Line Contents
================================================
6 27.8 MiB 27.8 MiB @app.route('/api', methods=['POST'])
7 @profile
8 def api():
9 617.3 MiB 589.5 MiB input_data = request.get_json(request.data)
10 617.3 MiB 0.0 MiB output_data = {"id": "FOO"}
11 617.3 MiB 0.0 MiB response = jsonify(output_data)
12 617.3 MiB 0.0 MiB return response
我错过了什么?是什么导致了这个大的内存峰值以及如何处理它?
【问题讨论】:
-
仍在追踪为什么,但在
request.get_json之后放置一个断点,如下所示:import pdb; pdb.set_trace()。然后执行此操作:import sys; sys.getsizeof(input_data['file_content'])。您会看到它大约为 1.2GB。随后的请求似乎也会增加它看起来的内存占用,直到它被垃圾收集。 -
@wholevinski 我已经尝试按照您的建议插入断点,
sys.getsizeof(input_data['file_content'])报告的数字与客户端中的sys.getsizeof(xml_string)相同(~283 MB)。看起来峰值发生在断点之前,request.get_json是罪魁祸首。 -
嗯,是的,我在切换 python3 时看到了与您相同的行为。我只是碰巧在 python2 virtualenv 上尝试让
heapy使用它。但是,是的,看起来get_json是罪魁祸首。我想它在反序列化时会创建一个新字符串,这将占到大小的 2 倍。 -
实际上,在切换回 python 3 后,我现在看到内存占用是原始
file_content大小的 2 倍,而不是一个巨大的峰值。后续请求不为我清除,所以你确定它不是累积的吗?你可以重新启动你的 app.py 吗?编辑:看起来它最终会被 GC 清除。 -
@wholevinski 我每次都在运行这个应用程序。我对报告的 ~618 MB 内存使用情况很好,但对 ~2.8 GB 的峰值不满意,由于某种原因在分析时无法跟踪。