8.5K Star! 檢查 Python 代碼內(nèi)存分配的利器
簡介
開發(fā)者可以根據(jù)需要,生成多種統(tǒng)計報告,觀察程序的內(nèi)存分配。
1.總結(jié)報告
該報告會把多個線程的內(nèi)存分配情況顯示到同一個表格中,own memory?表示每個函數(shù)占用的內(nèi)存,total memory?表示函數(shù)本身及其調(diào)用其他函數(shù)所占用的內(nèi)存總量,allocation count表示暫時未釋放的內(nèi)存?zhèn)€數(shù)。
總結(jié)報告
2.火焰圖報告
?該報告可以將內(nèi)存分配數(shù)據(jù)可視化展示?;鹧鎴D的第一層是占用內(nèi)存的函數(shù), 寬度越大,則占用的內(nèi)存越多;每一層的函數(shù)都被其下一層的函數(shù)所調(diào)用,依次類推。
- 示例代碼:
def a(n):
return b(n)
def b(n):
return [c(n), d(n)]
def c(n):
return "a" * n
def d(n):
return "a" * n
a(100000)
- 生成的火焰圖
火焰圖報告
由該圖可以看出,函數(shù)a調(diào)用了函數(shù)b,函數(shù)b調(diào)用了函數(shù)c和函數(shù)d。且第一層函數(shù)c 和函數(shù)d所占的寬度相同,表示c和d占用的內(nèi)存一樣。
3.表格報告
該報告以表格的形式展示程序的內(nèi)存使用情況。Thread ID?表示對應的線程,Size?表示占用的內(nèi)存總數(shù),Allocator?表示占用內(nèi)存的函數(shù),Location表示函數(shù)所在的位置。同時,還可以對每一列的數(shù)據(jù)進行排序。
表格報告
4.樹形報告
該報告可以清晰的顯示出程序的調(diào)用層次。樹形報告中根節(jié)點中的內(nèi)存總量和所占百分比 只是針對于圖中展示的數(shù)據(jù),占用內(nèi)存小的不在圖中。
樹形報告
5.統(tǒng)計報告
該報告可以顯示程序內(nèi)存使用情況的詳細信息,包括分配的內(nèi)存總量、分配類型(例如MALLOC, CALLOC)等。
統(tǒng)計報告
項目地址
https://github.com/bloomberg/memray
安裝
目前只能在Linux平臺上使用Memray。由于Memray使用了C語言,發(fā)布的版本 是二進制的,所以得先在系統(tǒng)上安裝二進制編譯工具。隨后在Python3.7+的環(huán)境 下安裝Memray:
python3 -m pip install memray
如果你想安裝開發(fā)版本的Memray,首先要在系統(tǒng)上安裝二進制工具:libunwind 和liblz4,隨后克隆項目并運行如下命令進行安裝:
git clone git@github.com:bloomberg/memray.git memray
cd memray
python3 -m venv ../memray-env/ # just an example, put this wherever you want
source ../memray-env/bin/activate
python3 -m pip install --upgrade pip
python3 -m pip install -e . -r requirements-test.txt -r requirements-extra.txt
使用
1.基本使用
我們可以通過以下命令來追蹤python代碼的內(nèi)存分配情況,my_script.py就是要分析的文件:
python3 -m memray run my_script.py
也可以把memray當作命令行工具使用,例如:
memray run my_script.py
memray run -m my_module
以上命令會輸出一個二進制文件,隨后我們可以根據(jù)需要生成統(tǒng)計報告。假如我們想生成一個總結(jié)報告,那么可以運行如下命令:
memray summary my_script.bin
會生成程序內(nèi)存分配的總結(jié)報告:
總結(jié)報告
不同的報告形式在簡介部分都有展示,請讀者自行查看。
2.分析C/C++代碼的內(nèi)存分配
當要使用Memray分析numpy或者pandas這種包含C代碼的模塊時,我們可以運行如下命令:
memray run --native my_script.py
從而直觀的看到Python代碼分配了多少內(nèi)存,擴展模塊分配了多少內(nèi)存。
假如我們在一個文件中使用了Numpy,當我們不使用--native時,生成的統(tǒng)計報告如下圖:
統(tǒng)計報告
從圖中可以看出在計算Numpy數(shù)組時分配了內(nèi)存,但不清楚是Numpy還是Python解釋器分配了內(nèi)存。通過使用--native命令,就可以得到一個 更全面的報告,如圖所示:
native報告
從圖中可以看到Numpy中C模塊的調(diào)用情況,當添加Numpy數(shù)組后,產(chǎn)生了內(nèi)存分配。我們可以通過文件的后綴名區(qū)分Python模塊和C模塊。
3.在代碼運行時查看內(nèi)存分配變化
Memray還支持動態(tài)查看Python代碼的內(nèi)存分配情況,我們只需使用以下命令:
memray run --live my_script.py
在這種模式下,開發(fā)者可以調(diào)試運行時間較長的代碼。下圖即為文件運行時的內(nèi)存分配情況:
Live模式
4.結(jié)果排序
統(tǒng)計報告中的結(jié)果通常是根據(jù)分配的總內(nèi)存,從大到小依次排列。我們可以改變排序條件:
- t (默認): 根據(jù)總內(nèi)存排列
- o: 根據(jù)每個函數(shù)占用的內(nèi)存排列
- a: 根據(jù)未釋放的內(nèi)存?zhèn)€數(shù)進行排列
5.查看其他線程
使用live命令默認展示的是主線程的內(nèi)存分配情況,我們可以通過左右箭頭切換到其他線程。
其他線程
6.API
除了使用memray run查看Python代碼的內(nèi)存分配,還可以在Python程序中使用memray。
import memray
with memray.Tracker("output_file.bin"):
print("Allocations will be tracked until the with block ends")
更多細節(jié)可以查看相關(guān)API文檔[1]。
后記
在我們平時編寫 Python 代碼的過程中,有時候只考慮到了業(yè)務功能的實現(xiàn),而忽視了代碼的合理性與規(guī)范性,例如內(nèi)存分配就是一個很重要的點,合理的內(nèi)存分配有助于 提升項目的運行速度。Memray 就是一個支持查看Python代碼內(nèi)存分配的工具,它的便捷之處在于:我們可以根據(jù)需要,生成多種分析報告,從而直觀的了解到自己代碼的內(nèi)存分配情況,避免發(fā)生內(nèi)存泄露現(xiàn)象。