今回は、Pythonのガベージコレクションの概念について紹介します。
ガベージコレクションとは、Pythonが自動的にメモリを管理する方法です。
これは参照カウンターを用いて行われます。
そこで、ガベージコレクションの概念に入る前に、参照カウンタとは何かを理解することにしましょう。
この記事もチェック:Pythonのメモリ管理やガベージコレクションの仕組みを分かりやすく解説する
Pythonの参照カウンタとは?
参照カウンタとは、実行中のプログラム内でオブジェクトへの参照が行われた回数のことです。
これによってPythonコンパイラは、いつ変数が使われ、いつメモリからオブジェクトを削除しても安全か知ることができます。
これにより、プログラマはシステムリソースを埋め尽くすオブジェクトを追跡する仕事を減らし、プログラム作成に集中することができます。
Python のガベージコレクションはどのように動作するのか?
Pythonがバックエンドでガベージコレクションを行うために参照カウンターをどのように使うか理解しましょう。
これは簡単な例で理解できます。
まず、参照がどのようにカウントされるかを見ていき、次にPythonがオブジェクトへの参照がないときにどのように識別するかを見ていきます。
以下のコードを見てください。
# Increasing reference count as more variables link to it reference1 = 9 # Reference count for the value 9, becomes 1
reference2 = reference1 # Reference count for value 9 becomes 2
reference3 = reference1 # Reference count for value 9 becomes 3
# Decreasing reference count as the variable values change reference2 = 10 # Reference count for value 9 decreases to 2
reference3 = 5 # Reference count for value 9 decreases to 1
reference1 = 1 # Reference count for value 9 decreases to 0
# After the reference value becomes 0, the object is deleted from memory |
上記から明らかなように、最後の参照変数 “reference1 “の値が1に変更されると、値9はもうメモリ上で参照されなくなります。
Pythonインタプリタがコード全体から値への参照をなくすと、ガベージコレクタはその値へのメモリを解放して領域を確保します。
リファレンスサイクルとは?
もう一つ、参照サイクルと呼ばれる概念を見てみましょう。
これは、単純にオブジェクトを自分から参照するものです。
以下のコード例を見てください。
>>> a = []
>>> a.append(a) >>> print a
[[...]] |
さらに、a=[]とすると、空のリストが作成されます。
a.append()`は、このリストに何かを追加することを意味しています。
この場合、aです。
つまり、このオブジェクトに別の空のリストを追加することになります。
a` を呼び出すと、ここに2つのリストがあることがわかります。
つまり、空のリストを作成して、そのリストをオブジェクトの中で自分自身に追加しているのです。
つまり、オブジェクトの中にリストがあり、そのオブジェクトの中でリストが再び呼び出され、参照カウンタが1になるわけです。
しかし、もう a
は使っていないので、プログラムはもうそれを呼び出すことはありませんが、参照カウンターは1になっています。
Pythonには参照サイクルを削除する方法がありますが、すぐに削除されるわけではありません。
Pythonには参照サイクルを削除する方法があり、それはすぐには行われません。
何かを参照し、そして何かを参照しないということが何度も発生した後に削除されます。
この場合、何度も発生すると、pythonはガベージコレクションを実行し、メモリに入り、すべてのオブジェクトを調べます。
メモリに入ってすべてのオブジェクトを調べると、このオブジェクトが自分自身を参照していること、そしてもうこのオブジェクトを呼び出さないプログラムが、参照カウントが1であるにもかかわらず何も呼び出していないことがわかります。
そこで、先に進んでそれを削除します。
ガベージコレクションがいつ実行されるかはどうやって知るの?
さて、それは garbage collection
という Python モジュールを使って調べることができます。
ガベージコレクションモジュールをimport gcでインポートします。
そして、ガベージコレクションがいつ実行され、これらの参照サイクルをキャッチするかを知るための閾値を取得します。
gc.get_threshold()と入力すると、その情報を引き出すことができます。
import gc
gc.get_threshold() |
上記の2行のコードは以下の出力を表示します。
( 700 , 10 , 10 )
|
この出力を詳しく見てみましょう。
700」という値が意味するのは、何かを参照し、それを非参照にする参照が700回発生したら、Pythonは先に進み、参照サイクルを収集するということです。
簡単に言うと、700回発生したら、Pythonはスクリプトやアルゴリズムを実行して、メモリをクリーンアップします。
Pythonは、参照サイクルのために参照カウンタが1で止まっているときに、参照カウンタが0になると自動的にこれを実行します。
そして、700回発生した後にのみ、Pythonはサイクルをキャッチするためにガベージコレクションを実行します。
ガベージコレクションを手動で操作する
モジュールを使ってこれを変更することができます。
この記事ではその詳細を説明しませんが、変更できることだけは認識しておいてください。
そのためのコードは以下の通りです。
また、ユーザーはガベージコレクションをオンにしたりオフにしたりするだけでもいいのです。
このモジュールでできることはたくさんあります。
import gc
gc.disable() class Track:
def __init__( self ):
print ( "Intitialisting your object here" )
def __del__( self ):
print ( "Deleting and clearing memory" )
print ( "A" )
A = Track()
print ( "B" )
B = Track()
print ( "deleting here..." )
del A
del B
gc.collect() |
上のコードを説明すると、簡単に言うと、ガベージコレクタモジュールをインポートしたが、コードの最初に gc.disable()
を使ってガベージコレクションを無効にしているのです。
これは、自動ガベージコレクションが行われないようにするためです。
次に、コンストラクタとデストラクタだけのクラスTrackを定義しています。
AとBという2つのオブジェクトが定義され、定義後にコンソールに「Initialising your object here`」と表示されます。
オブジェクトは del
メソッドを使って削除します。
オブジェクトの削除に成功すると、コンソールに Deleting and clearing memory
と表示されます。
gc.collect()` メソッドは、ガベージコレクタがオブジェクトAとBによって占有されているメモリ空間を解放することを保証します。
ですから、そこに到達したとき、私たちがそれを使ってどれだけのことができるのかが分かるでしょう。
しかし、今のところ、pythonが我々のメモリ管理を維持するために非常に良い仕事をしてくれることだけは知っておいてください。
ガベージコレクションが行われない理由は何でしょうか?
もうひとつ指摘しておきたいのは、ガベージコレクションが実行されるにはメモリが必要なので、メモリが満杯に近く使い切られている場合、ガベージコレクションは実行されないということです。
ガベージコレクションを実行するにはメモリが必要だからです。
つまり、プログラムが非常に大きく、メモリを大量に使っていて、ガベージコレクションを実行するのに十分なメモリがないとすると、例外が大量に発生して、いろいろな問題が発生します。
だから、もしそういう問題がたくさんあるのなら、プログラムの少し前のほうでこれを実行するモジュールに慣れる必要があるかもしれない、ということだけは覚えておいてください。
まとめ
この記事が洞察に満ちたものであることを望みます。
ご意見・ご感想は、下のフィードバック欄からお願いします。