tracemalloc によるメモリープロファイリング
tracemalloc でメモリー割り当てを追跡し、リークを見つけます。
「tracemalloc によるメモリープロファイリング」はCoddyKit上の無料Python Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPython Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Python Academyコースには全4レッスンが含まれています。
tracemallocとは
tracemallocは、ファイル名と行番号ごとにPythonのメモリ割り当てを追跡する標準ライブラリモジュールです。
import tracemalloc
tracemalloc.start()
x = [i for i in range(100_000)]
current, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
print(f"Current: {current/1024:.1f} KB")
print(f"Peak: {peak/1024:.1f} KB")スナップショットの取得
スナップショットは、ある時点での現在のすべてのメモリ割り当てを記録します。2つのスナップショットを比較すると、その間に割り当てられたメモリを特定できます。
import tracemalloc
tracemalloc.start()
snap1 = tracemalloc.take_snapshot()
data = [{"key": str(i)} for i in range(10_000)]
snap2 = tracemalloc.take_snapshot()
stats = snap2.compare_to(snap1, "lineno")
for stat in stats[:5]:
print(stat)スナップショットのフィルタリング
統計情報をアプリケーションのコードだけに絞り込み、標準ライブラリを除外して表示します。
import tracemalloc
tracemalloc.start()
leak_function()
snap = tracemalloc.take_snapshot()
filters = [tracemalloc.Filter(True, "*/myapp/*")]
stats = snap.filter_traces(filters).statistics("lineno")
for stat in stats[:10]:
print(stat)メモリを多く消費する箇所
snapshot.statistics("lineno")または"traceback"を使用すると、行ごとまたは完全なトレースバックごとに、メモリを多く消費している箇所を確認できます。
import tracemalloc
tracemalloc.start(nframe=10) # track 10 frames deep
big_list = [i**2 for i in range(500_000)]
snap = tracemalloc.take_snapshot()
for stat in snap.statistics("traceback")[:3]:
print(stat)
for line in stat.traceback.format():
print(" ", line)メモリリークの特定
メモリリークが疑われる箇所の前後で2つのスナップショットを取得して比較します。スナップショット間で統計値が増加していれば、メモリリークの可能性があります。
import tracemalloc
tracemalloc.start()
snap_before = tracemalloc.take_snapshot()
for _ in range(100):
suspected_leaky_function()
snap_after = tracemalloc.take_snapshot()
diff = snap_after.compare_to(snap_before, "lineno")
for stat in diff[:5]:
print(stat)get_traced_memory()
tracemalloc.get_traced_memory()は(current, peak)というバイト数の組を返します。軽量な実行前後の確認に便利です。
import tracemalloc
tracemalloc.start()
before, _ = tracemalloc.get_traced_memory()
do_something()
after, peak = tracemalloc.get_traced_memory()
tracemalloc.stop()
print(f"Delta: {(after-before)/1024:.1f} KB, Peak: {peak/1024:.1f} KB")memory_profiler
memory_profilerは、CPUに対するline_profilerと同様に、行ごとのメモリ使用量を提供します。
# pip install memory_profiler
from memory_profiler import profile
@profile
def build_data():
data = [i**2 for i in range(100_000)]
filtered = [x for x in data if x % 2 == 0]
return filtered
build_data()
# python -m memory_profiler script.pymemray
memray(Bloomberg製)は、フレームグラフを出力できる高速なPythonメモリプロファイラです。
# pip install memray
# python -m memray run script.py
# python -m memray flamegraph memray-script.py.bin
# Generates an interactive HTML flamegraph
# showing allocations by call stackメモリ使用量の削減
一般的な手法には、リストの代わりにジェネレータを使う、__slots__を使う、数値データにarrayモジュールを使う、numpy配列を使う、クロージャで大きなオブジェクトを保持し続けない、といったものがあります。
# Instead of:
data = [process(x) for x in huge_list] # all in memory
# Use a generator:
def gen_data(lst):
for x in lst:
yield process(x)
for item in gen_data(huge_list):
consume(item) # one at a timesys.getsizeof()
sys.getsizeof(obj)は、オブジェクトが使用するメモリ量をバイト単位で返します(浅いサイズであり、参照先のオブジェクトは含みません)。
import sys
print(sys.getsizeof([])) # 56
print(sys.getsizeof([1,2,3])) # 88
print(sys.getsizeof("hello")) # 54
print(sys.getsizeof({})) # 64
# For deep size, use recursive measurement:
def deep_size(obj):
return sys.getsizeof(obj) + sum(
sys.getsizeof(v) for v in vars(obj).values()
if hasattr(obj, "__dict__")
)本番環境でのプロファイリング
本番環境ではnframesを小さく制限してtracemallocを実行し、オーバーヘッドを最小限に抑えます。後でオフライン分析できるよう、スナップショットをファイルに保存します。
import tracemalloc, pickle
tracemalloc.start(nframe=5) # low overhead
# ... serve some requests ...
snap = tracemalloc.take_snapshot()
with open("snap.pkl","wb") as f:
pickle.dump(snap, f)
# Analyse later offline確認問題
tracemalloc.get_traced_memory()が返す2つの値は何を表しますか。
まとめ
tracemalloc.start()とスナップショットを使ってメモリリークを特定します。compare_to()でスナップショットを比較します。行ごとの使用量の確認にはmemory_profilerを、フレームグラフの作成にはmemrayを使います。ジェネレータ、__slots__、NumPy配列を使ってメモリ使用量を削減します。
よくある質問
「tracemalloc によるメモリープロファイリング」レッスンは無料ですか?
はい。「tracemalloc によるメモリープロファイリング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Python Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Python Academyコースには全4レッスンが含まれています。
「tracemalloc によるメモリープロファイリング」で何を学びますか?
tracemalloc でメモリー割り当てを追跡し、リークを見つけます。 ブラウザで直接実行するハンズオンコードでPython Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Python Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPython Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「tracemalloc によるメモリープロファイリング」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPython Academyレッスンでコードを書いて実行できますか?
はい。すべてのPython Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- CPython の参照カウント
- ガベージコレクターと循環参照
- cProfile と line_profiler によるプロファイリング
- tracemalloc によるメモリープロファイリング