Python跑循環(huán)時(shí)內(nèi)存泄露的解決方法
Python跑循環(huán)時(shí)內(nèi)存泄露
今天在用Tensorflow跑回歸做測試時(shí),僅僅需要循環(huán)四千多次 (補(bǔ)充說一句,我在個(gè)人PC上跑的)。運(yùn)行以后,我就吃飯去了。等我回來后,Console窗口直接亮紅了!??!
import numpy as np import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import tensorflow as tf import matplotlib.font_manager as fm myfont = fm.FontProperties(fname='C:/Windows/Fonts/simsun.ttc') sess = tf.Session() for j in range(0,4096): print('第' + str(j) + '次回歸') ......
此處忘了截圖,反正就是說Keras出現(xiàn)了什么什么錯(cuò)誤。然后我就順手重啟了工程。
接著就瞪著屏幕,為什么跑一半出錯(cuò)了???
這個(gè)時(shí)候我發(fā)現(xiàn)電腦管家的小火箭好像有點(diǎn)‘暴躁',打開任務(wù)管理器一看,果然。。。
Python占用內(nèi)存都快兩個(gè)G了,但是平時(shí)跑沒有占用這么多呀。我就猜想是不是因?yàn)榕苎h(huán),內(nèi)存沒有釋放,導(dǎo)致最后溢出,然后code就崩了。
抱著猜想的心態(tài)等了一分鐘,然后。。
WTF 飆到兩千三百多兆的占用了。結(jié)論很明顯了,就是沒有釋放內(nèi)存?。。?br />
這讓我想起來一個(gè)月前我在集群上并行GPU跑LSTM時(shí),出現(xiàn)了Out of memory,
這是2080ti呀,足足十一個(gè)G的內(nèi)存,雖然當(dāng)時(shí)我就用了一塊顯卡,但也不至于溢出吧。當(dāng)時(shí)沒有想到是這個(gè)問題,現(xiàn)在回想一下十有八九就是沒有釋放內(nèi)存。
至于為什么沒有釋放內(nèi)存,那就要從下面這個(gè)人出生的時(shí)候說起了—>
還記得那是一個(gè)月黑風(fēng)高夜晚,天空電閃雷鳴。。。。。。
hhh,開個(gè)玩笑,這個(gè)人是Python之父,不過我覺得接下來我要說的Python垃圾收集機(jī)制或多或少和他有一定的關(guān)系。
Python垃圾收集機(jī)制
現(xiàn)在的高級(jí)語言如java,c#等,都采用了垃圾收集機(jī)制,而不再是c,c++里用戶自己管理維護(hù)內(nèi)存的方式。自己管理內(nèi)存極其自由,可以任意申請(qǐng)內(nèi)存,但如同一把雙刃劍,為大量內(nèi)存泄露,懸空指針等bug埋下隱患。
對(duì)于一個(gè)字符串、列表、類甚至數(shù)值都是對(duì)象,且定位簡單易用的語言,自然不會(huì)讓用戶去處理如何分配回收內(nèi)存的問題。
python里也同java一樣采用了垃圾收集機(jī)制,不過不一樣的是:
python采用的是引用計(jì)數(shù)機(jī)制為主,標(biāo)記-清除和分代收集兩種機(jī)制為輔的策略。
Python中的內(nèi)存管理過程非常簡單。Python通過保持對(duì)每個(gè)對(duì)象在程序中的引用計(jì)數(shù)來處理其對(duì)象,這意味著每個(gè)對(duì)象存儲(chǔ)在程序中被引用的次數(shù)。此計(jì)數(shù)隨程序運(yùn)行時(shí)更新,并且當(dāng)計(jì)數(shù)為零時(shí),這意味著程序不再可訪問該計(jì)數(shù)。因此,解釋器可以回收和釋放該對(duì)象的內(nèi)存。
class User(object): def __del__(self): print("No reference left for {}".format(self)) user1 = User() user2 = user1 user3 = user1
在此示例中,我們制作了一個(gè)類和3個(gè)引用變量指向同一對(duì)象。讓我們將其可視化:
現(xiàn)在,讓變量user1,user2和user3指向None而不是User實(shí)例。
>>> user1 = None >>> user2 = None >>> user3 = None No reference left for <__main__.User object at 0x212bee9d9>
通過以上代碼,引用已更改為:
將最后一個(gè)變量分配user3給后None,該對(duì)象將被垃圾回收,這將調(diào)用該__del__函數(shù)。
從根本上講,每當(dāng)引用對(duì)象時(shí),Python對(duì)象的引用計(jì)數(shù)都會(huì)增加,而在取消引用對(duì)象時(shí),Python的引用計(jì)數(shù)會(huì)減少。如果對(duì)象的引用計(jì)數(shù)為0,則將釋放該對(duì)象的內(nèi)存。您程序的代碼無法禁用Python的引用計(jì)數(shù)。
python跑循環(huán)為什么沒有釋放內(nèi)存
有些人認(rèn)為,引用計(jì)數(shù)是A poor man's garbage collector 。很大一部分原因是它存在一些缺點(diǎn),其中就包括無法檢測到循環(huán)應(yīng)用。
如果在循環(huán)引用中的對(duì)象定義了__del__函數(shù),那么在循環(huán)引用中Python解釋器無法判斷析構(gòu)對(duì)象的順序,因此就不做處理,python gc不能進(jìn)行回收。
解決辦法
在提出解決問題之前,我們要先找到問題。因?yàn)槲疫@個(gè)Code需要畫圖,然后保存到本地。我就想是不是畫的圖導(dǎo)致占用過多內(nèi)存。
F_max = max(y_result) plt.figure(figsize=(15, 5)) plt.subplot(131) plt.scatter(Yp_data, Yt_data, alpha=0.8) plt.title(u'回歸前結(jié)果',fontproperties=myfont) plt.plot([0,F_max], [0,F_max], color = 'r') plt.subplot(132) plt.scatter(y_result, Yt_data, alpha=0.8) plt.title(u'回歸后結(jié)果',fontproperties=myfont) plt.plot([0,F_max], [0,F_max], color = 'r') plt.subplot(133) plt.plot(loss_vec, 'k-') plt.title('loss per Generation') plt.xlabel('Generation') plt.ylabel('Loss') plt.savefig('D:/lwt/py/Regression/figure/{} .png'.format(_type), dpi=100) plt.show()
有想法你就要去做是吧,然后我就加了兩行代碼。
plt.close('all') plt.clf()
這兩句是用來清除內(nèi)存中的圖像和清理掉 axes,并且為了盡可能的減少內(nèi)存占用,把plt.show()
都刪除了
然后運(yùn)行Code,打開任務(wù)管理器,測試是否管用。
貌似python占用的內(nèi)存是沒有之前上升的那么快了,不知道是不是心理作用hh。反正效果不明顯,看來得從別的地方下手了。
排除掉這個(gè)可能,那就是回收機(jī)制的鍋了。既然你不主動(dòng),那我就主動(dòng)點(diǎn)咯(猿式陰笑嘿嘿)。
for x in list(locals().keys())[:]: del locals()[x] gc.collect()
for循環(huán)就不要過多解釋了,先說del
語句的用法
del obj_name
這del
是一個(gè)Python關(guān)鍵字。而且,obj_name
可以是變量,用戶定義的對(duì)象,列表,列表中的項(xiàng),字典等??梢杂脕韯h除用戶定義的對(duì)象;刪除變量,列表和字典;從列表中刪除項(xiàng)目和切片;從字典中刪除鍵等等。具體用法大家可以查找相關(guān)文檔了解。
gc是python的垃圾回收器接口,gc.collect(generation=2)
若被調(diào)用時(shí)不包含參數(shù),則啟動(dòng)完全的垃圾回收。可選的參數(shù) generation 可以是一個(gè)整數(shù),指明需要回收哪一代(從 0 到 2 )的垃圾。當(dāng)參數(shù) generation 無效時(shí),會(huì)引發(fā) ValueError 異常。返回發(fā)現(xiàn)的不可達(dá)對(duì)象的數(shù)目。每當(dāng)運(yùn)行完整收集或最高代 (2) 收集時(shí),為多個(gè)內(nèi)置類型所維護(hù)的空閑列表會(huì)被清空。 由于特定類型特別是 float 的實(shí)現(xiàn),在某些空閑列表中并非所有項(xiàng)都會(huì)被釋放。
實(shí)測,有明顯的效果,內(nèi)存占用上升的速度明顯減小了,不過總體還是承上升的趨勢。相比之前,好太多了有沒有。
方法總比困難多,解決內(nèi)存泄漏也還有其他的辦法。我們還可以用objgraph、weakref等工具來分析并解決內(nèi)存泄露、循環(huán)引用問題。實(shí)在不行,還有一個(gè)超級(jí)硬核的辦法,自己動(dòng)手寫一個(gè)騰訊電腦管家小火箭的腳本,時(shí)不時(shí)的讓它上上天(騰訊記得打錢啊啊啊)。哈哈哈
在任何環(huán)境,不管是服務(wù)器,客戶端,內(nèi)存泄露都是非常嚴(yán)重的事情。如果是線上服務(wù)器,那么一定得有監(jiān)控,如果發(fā)現(xiàn)內(nèi)存使用率超過設(shè)置的閾值則立即報(bào)警,盡早發(fā)現(xiàn)些許還有救。
新的問題
不要強(qiáng)行收集垃圾太多次。這是因?yàn)?,即使要釋放?nèi)存,仍然需要花費(fèi)時(shí)間來評(píng)估對(duì)象是否符合垃圾收集條件。我在實(shí)測中的確發(fā)現(xiàn)運(yùn)行速度有些下降。
還有就是他會(huì)把全局的變量都刪了,以至于出現(xiàn)np
和pd
等導(dǎo)入的包都not defined。我的建議是把循環(huán)寫到函數(shù)里,做到只對(duì)某個(gè)函數(shù)起作用。
筆者作為一個(gè)學(xué)生也是剛接觸python不久,如有不對(duì)的地方還請(qǐng)指正,謝謝~
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
python import 上級(jí)目錄的導(dǎo)入
這篇文章主要介紹了python import 上級(jí)目錄的導(dǎo)入,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11解決pycharm運(yùn)行出錯(cuò),代碼正確結(jié)果不顯示的問題
今天小編就為大家分享一篇解決pycharm運(yùn)行出錯(cuò),代碼正確結(jié)果不顯示的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-11-11python+pandas+時(shí)間、日期以及時(shí)間序列處理方法
今天小編就為大家分享一篇python+pandas+時(shí)間、日期以及時(shí)間序列處理方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-07-07python高級(jí)內(nèi)置函數(shù)用法實(shí)例
在本篇文章里小編給大家整理的是一篇關(guān)于python高級(jí)內(nèi)置函數(shù)用法實(shí)例內(nèi)容,有興趣的朋友們可以學(xué)參考下。2021-09-09pytorch保存和加載模型的方法及如何load部分參數(shù)
本文總結(jié)了pytorch中保存和加載模型的方法,以及在保存的模型文件與新定義的模型的參數(shù)不一一對(duì)應(yīng)時(shí),我們?cè)撊绾渭虞d模型參數(shù),對(duì)pytorch保存和加載模型相關(guān)知識(shí)感興趣的朋友一起看看吧2024-03-03超級(jí)詳細(xì)實(shí)用的pycharm常用快捷鍵
本文詳細(xì)總結(jié)了Pycharm的常用快捷鍵,下文介紹使用方法和場景, 并不需要記憶這些快捷鍵, 你只需要知道有這些快捷鍵, 再需要用的時(shí)候查看一下, 用的多了自然也就記住了,需要的朋友可以參考下2021-05-05Python實(shí)現(xiàn)微信自動(dòng)回復(fù)信息的功能(根據(jù)不同信息回復(fù)對(duì)應(yīng)的信息)
這篇文章主要介紹了Python實(shí)現(xiàn)微信自動(dòng)回復(fù)信息的功能(根據(jù)不同信息回復(fù)對(duì)應(yīng)的信息),我們使用的第三方包是UIAutomation,結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09Python基礎(chǔ)之標(biāo)準(zhǔn)庫和常用的第三方庫案例教程
這篇文章主要介紹了Python基礎(chǔ)之標(biāo)準(zhǔn)庫和常用的第三方庫案例教程,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07