これに関する唯一のコメントgcmodule.c
は、Python ソースのファイルにあります。
注:可変オブジェクトの追跡解除について。特定の種類のコンテナーは参照サイクルに参加できないため、ガベージ コレクターによって追跡される必要はありません。これらのオブジェクトの追跡を解除すると、ガベージ コレクションのコストが削減されます。ただし、どのオブジェクトが追跡されない可能性があるかを判断するのは無料ではなく、ガベージ コレクションのメリットとコストを比較検討する必要があります。
コンテナーの追跡をいつ解除するかについては、次の 2 つの戦略が考えられます。
- コンテナが作成されたとき。
- コンテナーがガベージ コレクターによって検査されるとき。
不変オブジェクトのみを含むタプル (整数、文字列など、および再帰的に不変オブジェクトのタプル) を追跡する必要はありません。インタープリターは多数のタプルを作成しますが、その多くはガベージ コレクションまで存続しません。したがって、作成時に適格なタプルを追跡解除する価値はありません。
代わりに、空のタプルを除くすべてのタプルが作成時に追跡されます。ガベージ コレクション中に、生き残ったタプルを追跡解除できるかどうかが判断されます。タプルのすべてのコンテンツが追跡されていない場合、そのタプルは追跡されない可能性があります。タプルは、すべてのガベージ コレクション サイクルで追跡解除のために検査されます。タプルの追跡を解除するには、1 サイクル以上かかる場合があります。
不変オブジェクトのみを含む辞書も追跡する必要はありません。ディクショナリは、作成時に追跡されません。追跡された項目がディクショナリに (キーまたは値として) 挿入されると、ディクショナリが追跡されます。フル ガベージ コレクション (すべての世代) の間、コレクターは内容が追跡されていないディクショナリを追跡しません。
このモジュールは、オブジェクトの現在の追跡ステータスis_tracked(obj)
を返すpython 関数を提供します。その後のガベージ コレクションによって、オブジェクトの追跡ステータスが変更される場合があります。issue で特定のコンテナーの追跡解除が導入され、 issueに応じてアルゴリズムが改良されました。#4688
#14775
(リンクされた問題を参照して、追跡を解除できるようにするために導入された実際のコードを確認してください)
このコメントは少しあいまいですが、どのオブジェクトを「追跡解除」するかを選択するアルゴリズムが汎用コンテナに適用されるとは述べていません。これは、コードがtuple
s ( およびdict
s) のみをチェックし、そのサブクラスをチェックしないことを意味します。
これは、ファイルのコードで確認できます。
/* Try to untrack all currently tracked dictionaries */
static void
untrack_dicts(PyGC_Head *head)
{
PyGC_Head *next, *gc = head->gc.gc_next;
while (gc != head) {
PyObject *op = FROM_GC(gc);
next = gc->gc.gc_next;
if (PyDict_CheckExact(op))
_PyDict_MaybeUntrack(op);
gc = next;
}
}
PyDict_CheckExact
、およびの呼び出しに注意してください。
static void
move_unreachable(PyGC_Head *young, PyGC_Head *unreachable)
{
PyGC_Head *gc = young->gc.gc_next;
/* omissis */
if (PyTuple_CheckExact(op)) {
_PyTuple_MaybeUntrack(op);
}
への呼び出しに注意してくださいPyTuple_CheckExact
。
また、 のサブクラスはtuple
不変である必要はないことに注意してください。これは、このメカニズムを外部に拡張しtuple
たいdict
場合、汎用is_immutable
関数が必要になることを意味します。これは、Python のダイナミズムが原因で可能な場合でも、非常tuple
にコストがかかります (たとえば、クラスのメソッドは実行時に変更される可能性がありますが、組み込み型であるため、これは不可能です)。したがって、開発者はいくつかの特殊なケースのみに固執することを選択しました。
これは、非常に単純なクラスであるため、特殊なケースs も可能だと思います。たとえば、新しいクラスを作成しているnamedtuple
ときに呼び出すと、いくつかの問題が発生するため、GC はサブクラスをチェックする必要があります。そして、これは次のようなコードで問題になる可能性があります。namedtuple
class MyTuple(namedtuple('A', 'a b')):
# whatever code you want
pass
クラスは不変であるMyTuple
必要はないため、GC はクラスが の直接のサブクラスであることを確認してnamedtuple
安全を確保する必要があります。ただし、この状況には回避策があると確信しています。
namedtuple
s は python コアではなく標準ライブラリの一部であるため、おそらくそうではありませんでした。おそらく、開発者はコアを標準ライブラリのモジュールに依存させたくなかったのでしょう。
だから、あなたの質問に答えるには:
namedtuple
いいえ、それらの実装には、本質的にs の追跡を妨げるものは何もありません
- いいえ、彼らはこれを「単に見落とした」わけではないと思います。ただし、python 開発者だけが、それらを含めないことを選択した理由について明確な答えを出すことができました。私の推測では、彼らはそれが変更に十分な利益をもたらすとは考えておらず、コアを標準ライブラリに依存させたくなかったのです。