我們在 Zendesk 中大量使用 Python 來構建機器學習 (ML) 產品。我們在機器學習應用程序中遇到的常見性能問題之一是內存洩漏和峰值。Python 代碼通常通過分佈式處理框架(如Hadoop、Spark和AWS Batch)在容器內執行。每個容器都分配有固定數量的內存。一旦代碼執行超過指定的內存限制,容器將因內存不足錯誤而終止。 一個快速的解決方法是增加內存分配。然而,由於不可預測的內存峰值,這可能導致資源浪費並影響產品的穩定性。內存洩漏的原因可能包括: - 釋放洩漏記憶體的大物件
- 代碼中的引用循環
- 底層庫/C 擴展洩漏內存
一個有用的練習是分析應用程序的內存使用情況,以更好地了解代碼和所使用的底層包的空間效率。這篇文章涵蓋: - 分析時間應用程序的內存使用情況
- 如何檢查程序特定部分的內存使用情況
- 調試內存問題的技巧
分析時間內存您可以使用memory-profile包查看在 Python 代碼執行期間隨時間變化的內存使用情況。 - # install the required packages
- pip install memory_profiler
- pip install matplotlib
- # run the profiler to record the memory usage
- # sample 0.1s by defaut
- mprof run --include-children python fantastic_model_building_code.py
- # plot the recorded memory usage
- mprof plot --output memory-profile.png
複製代碼
A. 作為時間函數的內存配置文件選項include-children將包括通過父進程產生的任何子進程的內存使用情況。圖 A 顯示了一個迭代模型訓練過程,該過程導致內存隨著訓練數據批次的處理而循環增加。一旦垃圾收集開始,對象就會被釋放。 如果內存使用量不斷增長,則存在內存洩漏的潛在問題。這是一個虛擬示例腳本來說明這一點。
B. 內存佔用隨時間增加一旦內存使用量超過特定閾值,就可以使用pdb-mmem選項設置調試器斷點 ,這對於故障排除很方便。 某個時間點的內存轉儲了解程序中大對象的預期數量以及它們是否應該被複製和/或轉換為不同的格式非常重要。 為了進一步分析內存中的對象,可以使用muppy在程序中的某些代碼行中創建堆轉儲。 - # install muppy
- pip install pympler
- # Add to leaky code within python_script_being_profiled.py
- from pympler import muppy, summary
- all_objects = muppy.get_objects()
- sum1 = summary.summarize(all_objects)
- # Prints out a summary of the large objects
- summary.print_(sum1)
- # Get references to certain types of objects such as dataframe
- dataframes = [ao for ao in all_objects if isinstance(ao, pd.DataFrame)]
- for d in dataframes:
- print d.columns.values
- print len(d)
複製代碼
內存堆轉儲摘要示例另一個有用的內存分析庫是objgraph,它可以生成對像圖來檢查對象的沿襲。
有用的指針爭取快速反饋循環一個有用的方法是創建一個小的“測試用例”,它只運行有問題的內存洩漏代碼。如果完整的輸入數據運行時間很長,請考慮使用隨機採樣數據的子集。 在單獨的進程中運行內存密集型任務Python 不一定會立即將內存釋放回操作系統。為了確保在一段代碼執行後釋放內存,它需要在單獨的進程中運行。此頁面提供有關Python 垃圾收集的更多詳細信息。 調試器可以添加對對象的引用如果使用斷點調試器(例如pdb),則從調試器手動創建和引用的任何對像都將保留在內存配置文件中。這可能會產生內存洩漏的錯誤感覺,即對象未及時釋放。 注意可能會洩漏的包裹一些 Python 庫可能存在內存洩漏。例如,pandas 有很多已知的內存洩漏問題。 狩獵快樂!
原文
https://medium.com/zendesk-engin ... ations-6824d0518774
|