Python は 2 つの仕組みを使ってメモリを自動的に管理します。参照カウント(主要な手法)と、参照の循環を処理する循環ガベージコレクタです。メモリを手動で解放することはありませんが、その仕組みを理解することでメモリの挙動やリークを説明できます。
参照カウント — 主要な仕組み
sys
x = [, , ]
y = x
sys.getrefcount(x)
y
x
Python は 2 つの仕組みを使ってメモリを自動的に管理します。参照カウント(主要な手法)と、参照の循環を処理する循環ガベージコレクタです。メモリを手動で解放することはありませんが、その仕組みを理解することでメモリの挙動やリークを説明できます。
sys
x = [, , ]
y = x
sys.getrefcount(x)
y
x
すべてのオブジェクトは、いくつの参照が自分を指しているかを追跡します。カウントがゼロになると、メモリは即座に解放されます。これは決定論的で迅速です。何も参照しなくなった瞬間にオブジェクトは破棄されます。
# reference counting alone can't free this:
a = {}
b = {}
a["b"] = b # a references b
b["a"] = a # b references a → they reference EACH OTHER
del a, b # the names are gone, but the objects still reference each other
# → refcounts never reach 0 → they'd leak with refcounting alone
互いを参照する 2 つのオブジェクトは、到達不能になっても互いの参照カウントをゼロより上に保ち続けます。これは純粋な参照カウントでは回収できない循環です。
import gc
# the generational GC periodically finds and frees unreachable CYCLES
gc.collect() # manually trigger a collection
gc.get_count() # objects tracked per generation
Python の補助的な世代別ガベージコレクタは、こうした到達不能な循環を定期的に検出して解放します。これは世代別です。新しいオブジェクトほど頻繁にチェックされ(ほとんどのオブジェクトは早く死ぬ)、効率的です。
✓ Most memory is reclaimed promptly via reference counting
⚠️ Leaks still happen from REACHABLE references that outlive their usefulness:
- global caches/lists that only grow
- objects held by long-lived closures or class attributes
- registered callbacks/listeners never removed
GC は循環を処理しますが、まだ到達可能なオブジェクトを解放することはできません。実世界でよくある「リーク」は、参照を意図せず生かし続けてしまうこと(例: 増え続けるグローバルキャッシュ)です。
- Small integers (-5..256) and short strings are CACHED/interned (shared, reused)
- CPython uses memory pools (pymalloc) for small objects (efficiency)
Python のメモリモデル(迅速な参照カウントに加えて循環 GC)を理解すると、実際の挙動が説明できます。なぜオブジェクトは通常すぐに解放されるのか、なぜ参照の循環には GC が必要なのか、そして重要なこととして、なぜ Python における「メモリリーク」は、忘れられた解放処理ではなく到達可能な参照(増え続けるキャッシュ、残存するクロージャ、削除されないコールバック)から生じるのか、です。
この知識は、長時間稼働するサービスでのメモリ増加の診断や、メモリを意識したコードを書くために不可欠です。修正は通常、GC が肩代わりできる何かではなく、参照を断ち切ること(キャッシュに上限を設ける、登録を後始末する)であると知ることが鍵です。