CPython の参照カウント
CPython が参照カウントでオブジェクトのライフタイムを追跡する仕組みを理解します。
「CPython の参照カウント」はCoddyKit上の無料Python Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPython Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Python Academyコースには全4レッスンが含まれています。
参照カウントとは
CPythonは、すべてのオブジェクトの参照カウントを追跡します。カウントが0になると、オブジェクトは直ちに解放されます。これはPythonの主要なメモリ管理機構です。
import sys
x = [1, 2, 3]
print(sys.getrefcount(x)) # 2 (x + getrefcount arg)
y = x
print(sys.getrefcount(x)) # 3sys.getrefcount()
sys.getrefcount(obj) は現在の参照カウントを返します。注意点として、この関数を呼び出すと、関数の引数による参照が1つ追加されます。
import sys
a = "hello"
print(sys.getrefcount(a)) # baseline (may be high for interned strings)
b = a
print(sys.getrefcount(a)) # one more
del b
print(sys.getrefcount(a)) # back to baseline増加と減少
代入するたびにカウントは増加し、削除または再代入するたびに減少します。カウントが0になると、CPythonはオブジェクトのデアロケーターを呼び出します。
x = [] # refcount = 1
y = x # refcount = 2
z = [x] # refcount = 3 (list holds a reference)
del y # refcount = 2
z.clear() # refcount = 1
del x # refcount = 0 → deallocatedオブジェクトのインターニング
CPythonは小さな整数(-5から256)や多くの文字列リテラルをインターンし、同じオブジェクトを再利用します。is による比較でこれを確認できます。
a = 256
b = 256
print(a is b) # True (interned)
c = 257
d = 257
print(c is d) # may be False (not interned)弱参照
弱参照は参照カウントを増加させません。観察したいものの所有はせず、ガベージコレクションを妨げたくない場合に役立ちます。
import weakref
class BigObject:
pass
obj = BigObject()
ref = weakref.ref(obj)
print(ref()) # <BigObject instance>
del obj
print(ref()) # None (object was collected)参照サイクル
AがBを参照し、BがAを参照している場合、両方が到達不能になっても、どちらのカウントも0になりません。CPythonの循環GCがこれらを検出して回収します。
a = []
b = [a]
a.append(b) # cycle: a → b → a
del a, b
# Both are unreachable but refcount > 0
# The cyclic GC collects themgcモジュール
gc モジュールは循環ガベージコレクターを提供します。自動的に実行されますが、手動で起動したり無効にしたりすることもできます。
import gc
gc.collect() # force a collection cycle
print(gc.get_count()) # (gen0, gen1, gen2) allocation counts
print(gc.get_threshold()) # when each generation is collectedメモリプール(pymalloc)
CPythonは小さなオブジェクト(512バイト未満)を独自のメモリプール(pymalloc)から割り当てます。これは小さなオブジェクトごとに malloc を呼び出すより高速です。
# You do not call pymalloc directly — CPython uses it internally
# for all Python-level object allocations
# The pool pre-allocates large memory arenas
# and carves them into pools of fixed-size blocks__del__ファイナライザー
__del__ は、オブジェクトの参照カウントが0になったときに呼び出されます(サイクル内にある場合は、後で呼び出されることがあります)。重要なクリーンアップをこれに依存せず、代わりにコンテキストマネージャーを使用してください。
class Resource:
def __del__(self):
print(f"Freeing {self}")
# Better: use context manager
class SafeResource:
def __enter__(self): return self
def __exit__(self, *a): self.cleanup()__slots__によるコンパクトなオブジェクト
__slots__ を持つオブジェクトはメモリ使用量と割り当て回数が少なく、GCへの負荷を軽減します。
import sys
class Reg:
def __init__(self, x, y): self.x, self.y = x, y
class Slotted:
__slots__ = ("x","y")
def __init__(self, x, y): self.x, self.y = x, y
print(sys.getsizeof(Reg(1,2))) # ~48 + dict overhead
print(sys.getsizeof(Slotted(1,2))) # ~48 (no dict)循環GCの無効化
参照サイクルを作成しないプログラムでは、循環GCを無効にするとスループットが向上する場合があります。
import gc
gc.disable() # no cyclic GC — objects are only freed by refcounting
# Use only if you KNOW no cycles are created
# (pure functional/immutable data)
gc.enable() # re-enable確認問題
CPythonがオブジェクトを直ちに解放するのはいつですか?
まとめ
CPythonは参照カウントによってオブジェクトを追跡します。カウントが0になると、直ちに解放されます。参照サイクルは循環GC(gc モジュール)によって処理されます。重要なクリーンアップには __del__ を使用せず、コンテキストマネージャーを使用してください。オブジェクトごとのメモリ使用量を減らすには __slots__ を使用します。
よくある質問
「CPython の参照カウント」レッスンは無料ですか?
はい。「CPython の参照カウント」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Python Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Python Academyコースには全4レッスンが含まれています。
「CPython の参照カウント」で何を学びますか?
CPython が参照カウントでオブジェクトのライフタイムを追跡する仕組みを理解します。 ブラウザで直接実行するハンズオンコードでPython Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Python Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPython Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。
「CPython の参照カウント」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPython Academyレッスンでコードを書いて実行できますか?
はい。すべてのPython Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。