2024-09-14|閱讀時間 ‧ 約 22 分鐘

[Python]使用memory_profiler測試優化前後的程式記憶體使用量

通過 memory_profiler 來測試優化前後的程式。

上一篇memory_profiler工具的說明介紹


以下是一個記憶體使用量較高的原始程式碼,接著對程式進行優化後,再次使用 memory_profiler 來比較優化前後的記憶體使用情況。

Python版本

3.11.3

1. 原始程式碼:未經優化

這個範例創建了多個大型列表來模擬高記憶體消耗,並展示如何使用 ,執行時間非常久請小心服用

memory_profiler 來分析每一行程式碼的記憶體使用情況。

from memory_profiler import profile

@profile
def create_large_list():
a = [i for i in range(10**7)] # 大列表佔用大量記憶體
b = [i * 2 for i in a] # 創建另一個大列表
c = a.copy() # 複製列表
return b, c

if __name__ == '__main__':
create_large_list()

解析:

  • 這段程式創建了一個包含 1000 萬個元素的列表 a,然後用它來創建另一個大列表 bc。這些操作會耗費大量記憶體。
  • 運行這段程式時,使用 memory_profiler 可以查看每一步操作的記憶體增長情況。

運行命令:

python -m memory_profiler your_script.py

2. 優化後程式碼:減少記憶體使用

在這裡,我們將通過一些方法來優化記憶體使用。比如,使用生成器(generator)來避免同時在記憶體中保留多個大型列表。

from memory_profiler import profile

# 使用生成器來優化記憶體
@profile
def create_large_list_optimized():
a = (i for i in range(10**7)) # 使用生成器而不是列表
b = (i * 2 for i in a) # 生成器來避免創建大列表
return b

if __name__ == '__main__':
create_large_list_optimized()

解析:

  • 這段程式使用了生成器表達式 (i for i in range(10**7)),來取代列表,生成器是惰性評估的,因此不會立即佔用大量記憶體,而是按需生成元素。
  • 生成器的「惰性評估」(也叫延遲求值)指的是生成器不會一次性生成所有結果,而是按需生成,也就是當你需要一個值時,它才計算並返回這個值,而不會提前計算或佔用額外的記憶體。
  • 這樣的優化大幅度降低了程式的記憶體使用量,特別是在處理大型數據時。

3. 比較優化前後的記憶體使用

使用 memory_profiler 來比較優化前後的記憶體使用情況:

優化前(未使用生成器)的輸出:

優化後(使用生成器)的輸出:


效益分析

  • 未優化版本:每次創建或複製列表時,記憶體的增量非常大(每次增加約 431.1MiB)。如果處理更大的數據集,這樣的記憶體的佔用會迅速增長。
  • 優化後版本:使用生成器後,記憶體使用幾乎沒有增加,因為生成器不會一次性將數據載入記憶體,而是隨需求逐步生成數據。

負值說明

  • 優化前(未使用生成器)的輸出:Line #5Line #6 顯示負的記憶體增量(-2526.2 MiB-17960.5 MiB),這是異常的情況。通常,這樣的負數是由於記憶體計算的誤差或者是Python分配和釋放記憶體機制的結果導致的。

可能的原因:

  1. Python 記憶體管理:Python 有自己的記憶體分配和釋放機制,尤其是垃圾回收系統。當你創建大數據結構時,Python 可能會隨著垃圾回收系統的運行,釋放不再使用的記憶體,導致計算出現這樣的異常結果。
  2. 系統記憶體波動:有時候系統的記憶體分配和釋放過程中也會出現一些波動,特別是在運行大規模記憶體操作時,可能會導致 memory_profiler 讀取記憶體的數據不穩定。


謝謝大家觀看,若喜歡的話,希望可以追蹤,點愛心給予鼓勵

[Python]使用memory_profiler測量 Python程式記憶體使用情況

分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.