Python3.12の新機能 Python 3.12の新機能(その6) PEP 683: 固定参照カウントによる永続オブジェクト

PEP 701: f文字列の形式定義PEP 695: 型パラメータ文法その他の型ヒント関連機能PEP 688: バッファープロトコルをPythonで利用可能にPEP 684: インタープリター別GILPEP 683: 固定参照カウントによる永続オブジェクトPEP 709: 内包式のインライン化

Pythonは、すべての変数などが参照しているオブジェクトを正確に把握し、それぞれのオブジェクトが参照されている数を厳密に記録しています。この、記録されている参照の数を、参照カウント と言います。参照カウントが 0 になると、そのオブジェクトはすでに利用されていないことが明らかなので、Pythonはそのオブジェクトを開放します。

オブジェクトの参照カウントは、sys.getrefcount() で調べられます。

次の例では、sys.getrefcount() を使って、True オブジェクトが参照されている数を調べています。起動した直後の状態ですが、すでに 202ヶ所から参照されています。

Python 3.11.7 (v3.11.7:fa7a6f2303, Dec  4 2023, 15:22:56) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getrefcount(True)
202

True を変数 var1 に代入すると、参照カウントが 1 増加します。

>>> var1 = True
>>> sys.getrefcount(True)
203

変数 var1 を削除するともとに戻ります。

>>> del var1
>>> sys.getrefcount(True)
202

同じことを、Python3.12でも実行してみましょう。

Python 3.12.0 (v3.12.0:0fb18b02c8, Oct  2 2023, 09:45:56) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getrefcount(True)
4294967295
>>> var1 = True
>>> sys.getrefcount(True)
4294967295
>>> del var1
>>> sys.getrefcount(True)
4294967295
>>>

なにをやっても参照カウントは変化しなくなってしまいました。

PEP 683 – Immortal Objects, Using a Fixed Refcount

Python3.12では、PEP 683: 固定参照カウントによる永続オブジェクト が導入され、特に利用頻度の高い一部の変更不能オブジェクト(None, True, False, -5 から 256までの整数や組み込みデータ型など)は、実行時に参照カウントを更新しないように変更されました。 対象オブジェクトの参照カウントは、常に 4294967295 (=0xFFFFFFFF) 固定となります。

インスタグラムでのメモリ削減効果

この変更は Django を利用している Instagramから提案されたものです。InstagramではDjangoのサーバプロセスを複数起動してサービスを提供していますが、本来ならばすべてのサーバで共有されているはずのメモリが徐々に共有されなくなり、サーバごとのメモリ使用量が時間とともに増大するという現象に悩まされていました。

image.png

(画像は Introducing Immortal Objects for Pythonから)

こういったサービスでは、まず最初に一つDjangoプロセスを起動し、そのプロセスをコピーして子プロセスを作成します。この方式では、子プロセスは親プロセスのメモリを共有するのでメモリ使用量を減らせるというメリットがありますが、Pythonの場合は各プロセスが参照カウントの更新を行うため、メモリを共有できずに子プロセスはそれぞれ専用のメモリを持つようになってしまいます。

しかし、None などの汎用的なオブジェクトを参照カウントの対象外とすれば、その部分のメモリは全く更新されなくなります。その結果、これまで更新されていた部分のメモリをすべてのプロセスで共有できるので、全体的なメモリ効率が大きく向上するようになりました。

image.png

(画像は Introducing Immortal Objects for Pythonから)

GIL除去に向けて

現在 Pythonでは PEP 703 グローバル・インタプリタ・ロックを除去可能に の解説Python 3.12の新機能(その5) PEP 684: インタープリター別GIL など、GILの影響を軽減する試みが行われています。参照カウントの更新はPythonがGILを必要とする大きな要因でもありますので、今回の変更は将来への大きな助けとなるでしょう。

Copyright © 2001-2023 python.jp Privacy Policy python_japan
Amazon.co.jpアソシエイト
Amazonで他のPython書籍を検索