PYTHON MEBY

Pythonでガーベジコレクションを制御(gc)

この記事では、Pythonのガーベジコレクションモジュール `gc` を使用して、ガーベジコレクションを制御する方法について説明します。`gc.collect()`、`gc.disable()`、`gc.enable()`、`gc.get_threshold()`、`gc.get_count()` などの関数について解説し、サンプルコードを通して理解を深めます。

目次

ガーベジコレクションとは?

Pythonでは、参照カウント方式と循環参照検出によるガーベジコレクションが組み込まれています。参照カウント方式は、オブジェクトへの参照数が0になると自動的にメモリから解放する仕組みです。循環参照が発生した場合、参照カウント方式だけではメモリリークが発生するため、Pythonは循環参照を検出し、メモリを解放する機構を持っています。`gc`モジュールを使うことで、このガーベジコレクションの動作を制御できます。

`gc` モジュールは、Python インタプリタのガーベジコレクタを制御するための関数を提供します。これにより、明示的にガーベジコレクションを実行したり、ガーベジコレクションを一時的に無効化したりできます。

gc.collect(): ガベージコレクションの実行

`gc.collect()` 関数は、ガーベジコレクションを強制的に実行します。通常は自動的に行われますが、メモリ使用量が多い状況や、特定のタイミングでメモリを解放したい場合に利用できます。

import gc

# オブジェクトを作成してメモリを消費
objects = [object() for _ in range(100000)]

# ガベージコレクションを実行
gc.collect()

# オブジェクトを削除
del objects

このコードでは、多くのオブジェクトを作成し、`gc.collect()` を呼び出すことで、それらのオブジェクトが解放され、メモリが回収されます。`del objects` を実行しても、実際にはメモリが解放されるのは、ガベージコレクタが実行された時です。`gc.collect()` を実行することで、メモリ解放のタイミングを制御できます。

gc.disable(): ガーベジコレクションの無効化

`gc.disable()` 関数は、ガーベジコレクションを無効化します。ガーベジコレクションを無効にすることで、パフォーマンスを向上させることができますが、メモリリークが発生する可能性があるため、注意が必要です。通常は、一時的に無効化し、必要に応じて再度有効化するのが良いでしょう。

import gc
gc.disable()

ガーベジコレクションを無効化した後、`gc.enable()` で有効化する必要があります。

gc.enable(): ガーベジコレクションの有効化

`gc.enable()` 関数は、`gc.disable()` で無効化したガーベジコレクションを再度有効化します。

import gc
gc.enable()

gc.get_threshold(): コレクション閾値の取得

`gc.get_threshold()` 関数は、ガーベジコレクションが実行されるための閾値を取得します。この閾値は、3つのタプル(generation 0, 1, 2)で表され、各世代のオブジェクト数が閾値を超えるとガーベジコレクションが実行されます。

import gc
threshold = gc.get_threshold()
print(threshold)

出力されるタプルは、各世代のオブジェクト数です。これらの値は、システムのメモリ状況に応じて変化します。

gc.get_count(): コレクション回数の取得

`gc.get_count()` 関数は、各世代のガーベジコレクションが実行された回数を取得します。

import gc
count = gc.get_count()
print(count)

出力されるタプルは、各世代のガーベジコレクションの実行回数です。

gc.set_debug(): デバッグ出力の設定

`gc.set_debug()` 関数は、ガーベジコレクションのデバッグ出力を設定します。デバッグレベルを設定することで、ガーベジコレクションの詳細な情報を出力させることができます。

import gc
gc.set_debug(gc.DEBUG_STATS) # 例: 統計情報を表示

実践例:大きなオブジェクトのメモリ管理

大きなオブジェクトを扱う場合、`gc.collect()` を明示的に呼び出すことで、メモリを効率的に管理することができます。ただし、頻繁に呼び出すとパフォーマンスに影響を与える可能性があるため、適切なタイミングで呼び出す必要があります。

import gc
import sys

# 大きなリストを作成
big_list = [i for i in range(1000000)]
print(sys.getsizeof(big_list))

# ガベージコレクションを実行
gc.collect()
del big_list
print(sys.getsizeof(big_list))

補足:弱参照

弱参照 (weakref) を使うことで、オブジェクトへの参照を維持しつつ、ガーベジコレクションの対象にすることができます。これにより、メモリリークを防ぎつつ、オブジェクトの参照を共有することができます。詳細は `weakref` モジュールを参照してください。

関連記事