IT评测·应用市场-qidao123.com技术社区

标题: Python Flask内存泄漏分析定位 [打印本页]

作者: 星球的眼睛    时间: 2024-11-2 08:55
标题: Python Flask内存泄漏分析定位
通过蓝图注册内存跟踪分析接口

示例代码如下,开启内存分析跟踪须要在Flask服务启动前注入环境变量
export PYTHONTRACEMALLOC=1
  1. from typing import Literal
  2. from flask import Blueprint, jsonify, request
  3. import tracemalloc
  4. import os
  5. import linecache
  6. snapshot = None
  7. run_path = os.path.dirname(__file__) # 根据实际需要修改为项目目录,目的是方便后续只追踪本项目的内存泄漏
  8. app_bus_blueprint = Blueprint('memory', __name__)
  9. def filter_traces(snapshot: tracemalloc.Snapshot, left_trace:Literal['only my code', 'all', 'beside my code']='only my code'):
  10.     filter_list = (
  11.         # tracemalloc.Filter(False, "<frozen importlib._bootstrap>"),
  12.         # tracemalloc.Filter(False, "<unknown>"),
  13.         # tracemalloc.Filter(False, "<frozen importlib._bootstrap_external>"),
  14.         tracemalloc.Filter(False, tracemalloc.__file__),
  15.         tracemalloc.Filter(False, linecache.__file__),
  16.         tracemalloc.Filter(False, f"*.vscode-server*"),
  17.         # tracemalloc.Filter(True, jober.__file__),
  18.     )
  19.     trace_store = {
  20.         'only my code': (
  21.             tracemalloc.Filter(True, f"{run_path}*"),
  22.         ),
  23.         'all': (),
  24.         'beside my code':(
  25.             tracemalloc.Filter(False, f"{run_path}*"),
  26.         )
  27.     }
  28.     filter_list = filter_list + trace_store[left_trace]
  29.     snapshot = snapshot.filter_traces(filter_list)
  30.     return snapshot
  31. def display_top(snapshot: tracemalloc.Snapshot, key_type='lineno', limit=30):
  32.     lines = []
  33.     # snapshot = filter_traces(snapshot)
  34.     top_stats = snapshot.statistics(key_type)
  35.     lines.append("Top %s lines" % limit)
  36.     for index, stat in enumerate(top_stats[:limit], 1):
  37.         frame = stat.traceback[0]
  38.         lines.append("#%s: %s:%s: %.1f KiB"
  39.               % (index, frame.filename, frame.lineno, stat.size / 1024))
  40.         # lines.extend(stat.traceback.format())
  41.         line = linecache.getline(frame.filename, frame.lineno).strip()
  42.         if line:
  43.             lines.append('    %s' % line)
  44.         lines.append('---------------------------------')
  45.     other = top_stats[limit:]
  46.     if other:
  47.         size = sum(stat.size for stat in other)
  48.         lines.append("%s other: %.1f KiB" % (len(other), size / 1024))
  49.     total = sum(stat.size for stat in top_stats)
  50.     lines.append("Total allocated size: %.1f KiB" % (total / 1024))
  51.     return lines
  52. if str(os.getenv('PYTHONTRACEMALLOC', 0)) == '1':
  53.     tracemalloc.start(25)
  54.     @app_bus_blueprint.route('/memory_snapshot', methods=['POST', 'GET'], strict_slashes=False)
  55.     def memory_snapshot():
  56.         is_compare = isinstance(request.args.get('compare', False), str)
  57.         global snapshot
  58.         if not snapshot:
  59.             snapshot = tracemalloc.take_snapshot()
  60.             snapshot = filter_traces(snapshot)
  61.             return "Taken snapshot."
  62.         else:
  63.             lines = []
  64.             snapshot_current = tracemalloc.take_snapshot()
  65.             snapshot_current = filter_traces(snapshot_current)
  66.             if is_compare:
  67.                 top_stats = snapshot_current.compare_to(snapshot, 'lineno')
  68.                 # 过滤出只有增长的内存分配
  69.                 increased_stats = [stat for stat in top_stats if stat.size_diff > 0]
  70.                 # 取出增长最多的前10条数据
  71.                 top_increased_stats = sorted(increased_stats, key=lambda stat: stat.size_diff, reverse=True)
  72.                 for stat in top_increased_stats[:20]:
  73.                     lines.append("%s memory blocks: %.1f KiB" % (stat.count, stat.size / 1024))
  74.                     lines.extend(stat.traceback.format())
  75.                     # lines.append(str(stat))
  76.                     lines.append('-----------------------------------')
  77.                 total_increased = sum(stat.size_diff for stat in top_increased_stats)
  78.                 total_decreased = sum(stat.size_diff for stat in top_stats if stat.size_diff < 0)
  79.                 totol_allocated = sum(stat.size for stat in top_stats)
  80.                 lines.append(f"Total increased size: {total_increased / 1024:.1f} KiB")
  81.                 lines.append(f"Total decreased size: {total_decreased / 1024:.1f} KiB")
  82.                 lines.append(f"Absolute change size: {(total_increased + total_decreased) / 1024:.1f} KiB")
  83.                 lines.append(f"Total allocated size: {totol_allocated / 1024:.1f} KiB")
  84.             else:
  85.                 lines = display_top(snapshot_current, key_type='traceback')
  86.             snapshot = snapshot_current
  87.             return jsonify(lines)
复制代码
通过trace filter,可以选择’only my code’, ‘all’, 'beside my code’三种trace筛选策略,意思为:只跟踪我的工作区代码,所有,非我的代码/第三方包。
参考文章:

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com技术社区 (https://dis.qidao123.com/) Powered by Discuz! X3.4