欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

定位python內(nèi)存泄漏問題及解決

 更新時間:2023年11月07日 11:20:50   作者:Q博士  
這篇文章主要介紹了定位python內(nèi)存泄漏問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

背景

上周使用我的python web框架開發(fā)的第二個項目上線了,但是沒運(yùn)行幾天機(jī)器內(nèi)存就報警了,8G內(nèi)存使用了7G,懷疑有內(nèi)存泄漏,這個項目提供的功能就是一堆機(jī)器學(xué)習(xí)模型,對歷史數(shù)據(jù)進(jìn)行訓(xùn)練,挑選出最優(yōu)的5個模型,用作未來數(shù)據(jù)的預(yù)測,所以整個項目有著數(shù)據(jù)量大,運(yùn)行時間長的特點,就是把策略的離線工作搬到了線上。

定位內(nèi)存泄漏

第一步:確定是否有內(nèi)存泄漏

pympler檢查是否有內(nèi)存泄漏,程序入口處初始化該工具

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

接口返回處打印內(nèi)存差異,觀察內(nèi)存是否有泄漏

memory_tracker.print_diff() # 本次內(nèi)存和上次內(nèi)存塊的差異

我們用的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()

然后我們訪問接口,多觸發(fā)幾次,不用看前兩次,等輸出穩(wěn)定后,如果有內(nèi)存泄漏是如下輸出:

上圖顯示每次都有4類泄漏對象,一共泄漏約60K的內(nèi)存

如果沒有內(nèi)存泄漏,沒有數(shù)據(jù)輸出

第二步:確定內(nèi)心泄漏的代碼塊

我們確定程序有內(nèi)存泄漏后,就想辦法定位到代碼塊,就是我們自己寫的代碼,通過一步一步debug,注釋,return,continue等方式定位到造成泄漏的代碼塊,下面的代碼塊就是遍歷所有模型,然后挨個執(zhí)行訓(xùn)練方法,因為有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()

繼續(xù)訪問接口,多訪問幾次,輸出如下,直接定位到具體泄漏的代碼位置

圖中所有的泄漏點都定位到pandas庫,但是我用這些文件搜索內(nèi)存泄漏,都沒有搜到相關(guān)內(nèi)存泄漏的問題,所以得尋找誰調(diào)用這些地方,以

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

為例,我們要找到我們寫的代碼哪里調(diào)用觸發(fā)泄漏點

第四步:打印調(diào)用鏈

看了tracemalloc文檔也沒找到打印調(diào)用鏈的方法,后來靈機(jī)一動直接在這個文件加了下面代碼:

raise Exception("doctorq")

然后在接口里catch異常,添加logging.exception(e),然后觸發(fā)接口,打印堆棧信息:

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

定位到我們代碼觸發(fā)點如下:

調(diào)用的就是pandasRolling的一系列方法,然后搜索該方法是否有泄漏問題

第一個鏈接鏈接就是說這些方法(rolling.min/max)有泄漏,pandas rolling max leak memory,

具體因為啥泄漏的,也沒時間細(xì)究,反正issue里說回退到0.23.4是沒問題的,那么就回退試試:

pipenv install pandas==0.23.4

然后我們再用pympler定位有沒有內(nèi)存泄漏,pandas內(nèi)存泄漏的問題是修復(fù),剩下來就省memoryview的小泄漏了,明天繼續(xù)

總結(jié)

定位的過程略耗時,不過經(jīng)過這么一折騰,也算是有經(jīng)驗了,各種工具一陣堆,泄漏問題確定-定位代碼塊-定位泄漏點-搜索已知泄漏點-解決掉。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論