Python のGC(ガベージコレクション)と参照カウンタ
pythonを利用する上で、便利な表記などの個人的なメモである。基本的な部分は触れておらず、対象も自分が便利だなと思ったものに限定している。
github
- githubのjupyter notebook形式のファイルはこちら
google colaboratory
- google colaboratory で実行する場合はこちら
筆者の環境
!sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.6
BuildVersion: 18G103
!python -V
Python 3.8.5
GCとgetrefcount
GCの条件について色々する機会があったのでメモとして残しおく。
pythonは基本的にはガベージコレクションが採用されており、CやC++のように明示的にメモリを解放しなくても不要になったオブジェクトに関しては自動的に解放されるようになっている。それを実現している参照カウンタである。すべてのオブジェクトには、参照カウンタが内蔵されており、ある別のオブジェクトからそのオブジェクトへ参照があったら、参照カウンタをインクリメントする。また、その参照が削除されたらデクリメントを行い、カウンタが0になったらそのオブジェクトを解放する。
普段あまり参照カウンタには注意を払ったことがなかったのですが、今回この数字を元に色々解析したので、その概要だけ記録しておく。
import sys
class A():
def __init__(self, a, b):
self.a = a
self.b = b
オブジェクトが作成され、さらにsys.getrefcount
から参照されるので、参照カウンタは2になる。
a = A('a', 1)
sys.getrefcount(a)
2
bからも参照されるので3になる。
b = a
sys.getrefcount(a)
3
bを削除すると2になる。
b = None
sys.getrefcount(a)
2
インスタンス変数へ参照しても、インクリメントされない。
c = a.b
sys.getrefcount(a)
2
GC
通常、GCはdel
を行った後、gc.collet()
を明示的に行う。
ただ、del
後もメモリからその値が削除されるわけではなく、あくまでもpythonから参照できなくなるだけである。
import gc
b = A('b', 2)
del b
print(gc.get_stats()[2])
gc.collect()
print(gc.get_stats()[2])
{'collections': 3, 'collected': 664, 'uncollectable': 0}
{'collections': 4, 'collected': 810, 'uncollectable': 0}
gc後は参照カウンタは取得できない。
sys.getrefcount(b)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-31-e0d8d1240a7d> in <module>
----> 1 sys.getrefcount(b)
NameError: name 'b' is not defined