<一覧に戻る

リファレンスカウントとの違い

Pythonは、メモリ管理を行うためにガベージコレクションとリファレンスカウントの2つの主要な仕組みを使用しています。リファレンスカウントは、オブジェクトが何回参照されているかを追跡する方法であり、ガベージコレクションは、使用されていないオブジェクトを自動的に回収する仕組みです。この教材では、リファレンスカウントとガベージコレクションの違いを理解し、それぞれの役割を把握するためのサンプルコードを示します。

リファレンスカウントの基本

リファレンスカウント方式では、各オブジェクトはそのオブジェクトへの参照の数を持っています。参照が増えるとカウントが増加し、参照が減るとカウントが減少します。カウントがゼロになると、そのオブジェクトはメモリから解放されます。

サンプルコード

以下のコードは、リファレンスカウントの簡単な例を示しています。

class MyObject:
    def __init__(self, name):
        self.name = name
        print(f"{self.name} created")

    def __del__(self):
        print(f"{self.name} deleted")

# リファレンスカウントの確認
obj1 = MyObject("Object1")  # カウント1
obj2 = obj1                  # カウント2
print(f"Reference count for obj1: {obj1.__dict__}")

# obj2を削除
del obj2                    # カウント1
print(f"Reference count for obj1: {obj1.__dict__}")

# obj1を削除
del obj1                    # カウント0

コード解説

  1. MyObjectクラスを定義し、__init__メソッドでオブジェクトが生成されたことを通知します。
  2. __del__メソッドでオブジェクトが削除されたことを通知します。
  3. obj1を生成すると、リファレンスカウントは1になります。
  4. obj2obj1を参照すると、リファレンスカウントは2になります。
  5. del obj2を実行すると、obj1への参照が1つ減ります。
  6. 最後にdel obj1を実行すると、リファレンスカウントが0になり、オブジェクトが削除されます。

ガベージコレクションとの違い

リファレンスカウントは、オブジェクトのメモリ管理を行う一つの方法ですが、循環参照が存在する場合には効果がありません。循環参照とは、2つ以上のオブジェクトが互いに参照し合っている状態です。このような場合、リファレンスカウントではカウントがゼロにならず、オブジェクトが解放されないため、メモリリークが発生します。

循環参照の例

以下のサンプルコードは、循環参照がリファレンスカウントに与える影響を示します。

class Node:
    def __init__(self, name):
        self.name = name
        self.next = None
        print(f"{self.name} created")

    def __del__(self):
        print(f"{self.name} deleted")

# 循環参照の例
node1 = Node("Node1")
node2 = Node("Node2")

node1.next = node2
node2.next = node1  # 循環参照を作成

del node1
del node2  # この時点で、Node1とNode2はメモリから解放されません

コード解説

  1. Nodeクラスを定義し、__init__メソッドでオブジェクトが生成されたことを通知します。
  2. node1node2を生成し、互いに参照し合う循環参照を作成します。
  3. del node1del node2を実行しますが、循環参照のため、両方のオブジェクトはメモリから解放されません。

まとめ

リファレンスカウントは、オブジェクトがどれだけ参照されているかを追跡するシンプルなメモリ管理手法ですが、循環参照の問題に対処できないため、Pythonではガベージコレクションの仕組みも併用されています。ガベージコレクションは、使用されていないオブジェクトを自動的に回収し、メモリの効率的な管理を可能にします。このように、リファレンスカウントとガベージコレクションは、Pythonのメモリ管理において重要な役割を果たしています。

出力結果: