在工作中出現了一個未曾注意的問題:python的內存泄露問題,直接說問題和解決方式:
我遇到的問題出現內存泄露主要是因爲:使用c類型申請的變量數組造成的泄露,因爲申請(ctype.c_int*len)() 這類的數組的時候,沒有手動清除,導致在程序結束的時候,沒有自動回收,導致內存不斷的增加。
- python內存管理機制:
- 根據變量的引用計數,引用計數變爲0,在結束的時候,垃圾回收機制,會回收;
- 標記清除:如果兩個對象的引用計數都是1,兩個對象是循環引用的,雖然引用計數表現爲非0,但是實際上有效的引用計數爲0,這兩個變量都需要清除;
- 分代回收:垃圾回收分爲0,1,2代;這個就是有的變量存活時間比較長,這種變量往往不能及時回收;這種就需要手動清楚;
- 調優的手段:
- 避免循環引用
- 手動垃圾回收
- 調高垃圾回收閾值(沒有試驗,前兩個都用了。自認爲系統的設置一般不動,畢竟不是專業的運維的。)
- 內存的問題使用的方式:
- heap():在python3中引入guppy3,from guppy import hpy 然後打印出棧中內存的使用情況:print(hpy().heap())
- import objgraph,顯示內存中變量的增長情況使用objgraph.show_growth()
- memory_profiler:在函數的前邊添加@profile 顯示內存的變化,我這裏沒有用這個。
- 使用tracemalloc,查看沒有釋放內存的變量和位置,這是我主要使用的方式,
- 使用tracker,先查看是否有內存泄露,
-
from pympler import tracker,summary,muppy
-
memory_tracer = tracker.SummaryTracker()
- 程序流程
-
查看是否有內存泄露:memory_tracer.print_diff()
-
- 使用tracemalloc 查看泄露的位置
- import tracemalloc
- tracemalloc.start() 運行的程序
- snapshot1 = tracemalloc.take_snapshot()
- top_stats = snapshot1.statistics('lineno') #定位變量的名字和位置
- for stat in top_stats[:limit]: #limit:自己定義個數,要顯示的個數
- print(stat)
- 根據這個可以找到沒有釋放掉位置,找到變量,在使用完變量後,要手動銷燬,del +變量的名字
- 在結束後使用gc.collect(),釋放掉需要釋放的變量。
- 使用tracker,先查看是否有內存泄露,