定位python内存泄漏问题及解决

 更新时间:2023年11月07日 11:20:50   作者:Q博士  
这篇文章主要介绍了定位python内存泄漏问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

背景

上周使用我的python web框架开发的第二个项目上线了,但是没运行几天机器内存就报警了,8G内存使用了7G,怀疑有内存泄漏,这个项目提供的功能就是一堆机器学习模型,对历史数据进行训练,挑选出最优的5个模型,用作未来数据的预测,所以整个项目有着数据量大,运行时间长的特点,就是把策略的离线工作搬到了线上。

定位内存泄漏

第一步:确定是否有内存泄漏

pympler检查是否有内存泄漏,程序入口处初始化该工具

from pympler import tracker,summary,muppy
memory_tracker = tracker.SummaryTracker()

接口返回处打印内存差异,观察内存是否有泄漏

memory_tracker.print_diff() # 本次内存和上次内存块的差异

我们用的sanic,所以直接在main.py文件添加如下代码:

 from pympler import tracker,summary,muppy
 memory_tracker = tracker.SummaryTracker()

 @app.middleware('request')
 async def set_request_id(request):
     log_id = request.headers.get('log-id')
     threading.currentThread().logid = log_id
     gc.collect()
     memory_tracker.print_diff()

然后我们访问接口,多触发几次,不用看前两次,等输出稳定后,如果有内存泄漏是如下输出:

上图显示每次都有4类泄漏对象,一共泄漏约60K的内存

如果没有内存泄漏,没有数据输出

第二步:确定内心泄漏的代码块

我们确定程序有内存泄漏后,就想办法定位到代码块,就是我们自己写的代码,通过一步一步debug,注释,returncontinue等方式定位到造成泄漏的代码块,下面的代码块就是遍历所有模型,然后挨个执行训练方法,因为有20多个模型,我不能挨个注释每次对象来定位,卡在这里了。

第三步:确定泄漏点

tracemalloc定位泄漏点,python3.7.3自带,在main.py中添加如下代码:

tracemalloc.start(25)
snapshot = tracemalloc.take_snapshot()
@app.middleware('response')
async def print_on_response(request, response):
    global snapshot
    gc.collect()
    snapshot1 = tracemalloc.take_snapshot()
    top_stats = snapshot1.compare_to(snapshot, 'lineno')
    print("[ Top 10 differences ]")
 	for stat in top_stats[:10]:
    	 if stat.size_diff < 0:
			continue
 		 print(stat)
 	snapshot = tracemalloc.take_snapshot()

继续访问接口,多访问几次,输出如下,直接定位到具体泄漏的代码位置

图中所有的泄漏点都定位到pandas库,但是我用这些文件搜索内存泄漏,都没有搜到相关内存泄漏的问题,所以得寻找谁调用这些地方,以

/home/doctorq/.local/share/virtualenvs/scscore-K9x97I77/lib/python3.7/site-packages/pandas/core/window.py:859

为例,我们要找到我们写的代码哪里调用触发泄漏点

第四步:打印调用链

看了tracemalloc文档也没找到打印调用链的方法,后来灵机一动直接在这个文件加了下面代码:

raise Exception("doctorq")

然后在接口里catch异常,添加logging.exception(e),然后触发接口,打印堆栈信息:

ERROR:root:doctorq
Traceback (most recent call last):
  File "/home/doctorq/python-dev/scscore/src/forecasting/forecast.py", line 83, in update_method
    n_fraction=n_fraction)
  File "/home/doctorq/python-dev/scscore/src/forecasting/trainer.py", line 113, in training
    n_fraction=n_fraction)
  File "/home/doctorq/python-dev/scscore/src/forecasting/trainer.py", line 205, in train_machine_learning_model
    is_train=True).dropna()
  File "/home/doctorq/python-dev/scscore/src/feature_engineering/features.py", line 34, in get_feature
    history_same_periods=history_same_periods, zero_replace=zero_replace)
  File "/home/doctorq/python-dev/scscore/src/feature_engineering/sale_relate_feature.py", line 65, in get_feature
    store_and_sku=store_and_sku)
  File "/home/doctorq/python-dev/scscore/src/feature_engineering/sale_relate_feature.py", line 85, in get_rolling_feature
    rolling_result = self.get_rolling_result(window, rolling_obj, rolling_types)
  File "/home/doctorq/python-dev/scscore/src/feature_engineering/sale_relate_feature.py", line 169, in get_rolling_result
    rolling_result = self.rolling__(rolling_obj, rolling_type)
  File "/home/doctorq/python-dev/scscore/src/feature_engineering/sale_relate_feature.py", line 190, in rolling__
    return rolling_obj.min()
  File "/home/doctorq/.local/share/virtualenvs/scscore-K9x97I77/lib/python3.7/site-packages/pandas/core/window.py", line 1723, in min
    return super(Rolling, self).min(*args, **kwargs)
  File "/home/doctorq/.local/share/virtualenvs/scscore-K9x97I77/lib/python3.7/site-packages/pandas/core/window.py", line 1069, in min
    return self._apply('roll_min', 'min', **kwargs)
  File "/home/doctorq/.local/share/virtualenvs/scscore-K9x97I77/lib/python3.7/site-packages/pandas/core/window.py", line 879, in _apply
    result = np.apply_along_axis(calc, self.axis, values)
  File "/home/doctorq/.local/share/virtualenvs/scscore-K9x97I77/lib/python3.7/site-packages/numpy/lib/shape_base.py", line 380, in apply_along_axis
    res = asanyarray(func1d(inarr_view[ind0], *args, **kwargs))
  File "/home/doctorq/.local/share/virtualenvs/scscore-K9x97I77/lib/python3.7/site-packages/pandas/core/window.py", line 875, in calc
    closed=self.closed)
  File "/home/doctorq/.local/share/virtualenvs/scscore-K9x97I77/lib/python3.7/site-packages/pandas/core/window.py", line 858, in func
    raise Exception("doctorq")
Exception: doctorq

定位到我们代码触发点如下:

调用的就是pandasRolling的一系列方法,然后搜索该方法是否有泄漏问题

第一个链接链接就是说这些方法(rolling.min/max)有泄漏,pandas rolling max leak memory,

具体因为啥泄漏的,也没时间细究,反正issue里说回退到0.23.4是没问题的,那么就回退试试:

pipenv install pandas==0.23.4

然后我们再用pympler定位有没有内存泄漏,pandas内存泄漏的问题是修复,剩下来就省memoryview的小泄漏了,明天继续

总结

定位的过程略耗时,不过经过这么一折腾,也算是有经验了,各种工具一阵堆,泄漏问题确定-定位代码块-定位泄漏点-搜索已知泄漏点-解决掉。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Python一些基本的图像操作和处理总结

    Python一些基本的图像操作和处理总结

    今天给大家带来的是关于Python的相关知识,文章围绕着Python图像操作和处理展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • 无法找到VS Code Python解释器的几种解决办法

    无法找到VS Code Python解释器的几种解决办法

    这篇文章主要介绍了无法找到VS Code Python解释器的几种解决办法,文中介绍了三种方法,并对比Python3.12.5与3.9.6版本的优劣,需要的朋友可以参考下
    2025-05-05
  • VSCode搭建Django开发环境的图文步骤

    VSCode搭建Django开发环境的图文步骤

    本篇介绍在vscode环境下搭建Django开发环境的详细步骤,包括Python、Django、VSCode等,以及它们的安装和配置方法,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • pyqt 多窗口之间的相互调用方法

    pyqt 多窗口之间的相互调用方法

    今天小编就为大家分享一篇pyqt 多窗口之间的相互调用方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-06-06
  • 浅谈keras使用预训练模型vgg16分类,损失和准确度不变

    浅谈keras使用预训练模型vgg16分类,损失和准确度不变

    这篇文章主要介绍了浅谈keras使用预训练模型vgg16分类,损失和准确度不变,具有很好的参考价值,希望对大家有所帮助。一起跟随小编小编过来看看吧
    2020-07-07
  • 纯Python实现遗传算法详解

    纯Python实现遗传算法详解

    遗传算法(GA)是七十年代被霍兰德提出来的,那还是8086的时代,但在如今的3nm时代,仍然散发着经典的光辉,下面我们就来看看如何利用Python实现遗传算法吧
    2023-08-08
  • Python 调用PIL库失败的解决方法

    Python 调用PIL库失败的解决方法

    今天小编就为大家分享一篇Python 调用PIL库失败的解决方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-01-01
  • python命令行引导用户填写可用的ip地址和端口号实现

    python命令行引导用户填写可用的ip地址和端口号实现

    这篇文章主要为大家介绍了python命令行引导用户填写可用的ip地址和端口号实现详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • Python连接Hadoop数据中遇到的各种坑(汇总)

    Python连接Hadoop数据中遇到的各种坑(汇总)

    这篇文章主要介绍了Python连接Hadoop数据中遇到的各种坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • Pytest自定义用例执行顺序(推荐)

    Pytest自定义用例执行顺序(推荐)

    github 上有个 pytest-ordering 插件可以控制用例的执行顺序,本文给大家介绍了Pytest自定义用例执行顺序,需要的朋友可以参考下
    2021-12-12

最新评论