Pythonを使っていて, 不要なオブジェクトがメモリを圧迫しないようにするためにdelを使うことがあるが以下のような疑問がわく.
- delで削除されるのは変数自体なのか. その変数が指すオブジェクトの中身なのか.
- 例えば,
a = Obj()の時にdel aを呼び出したら,a = Noneになるのかaがそもそも宣言されていない状態になるのか.
- 例えば,
- delで削除しなくてもガベージコレクションでどうせ削除されるのではないか.
- ガベージコレクションがどのようなタイミングで呼ばれているのか
この疑問はdelやガベージコレクションに対する理解が十分にできていないことから生まれている. この記事では, それぞれの仕組みを詳しく見ていく.
Delステートメント
delステートメントはEBNF記法で以下のように定義される[1].
del_stmt: "del" target_listここでtarget_listの定義を確認しておく[1].
target_list: target ("," target)* [","]
target: identifier
| "(" [target_list] ")"
| "[" [target_list] "]"
| attributeref
| subscription
| "*" target“Deletion of a target list recursively deletes each target, from left to right.”と記載されているため[1], target_listが単一のtargetのみからなる場合を考える.
targetの種類によって削除の振る舞いは異なる.
削除対象がidentifierの時
削除対象がidentifierの場合は, ネームスペースからその名前のbindingを削除する. 以下の文章ではnameとして記載されているが, nameはidentifierとkeywordを合わせたものであることから[1], この文脈ではnameがidentifierを指していると考えていいだろう.
Deletion of a name removes the binding of that name from the local or global namespace, depending on whether the name occurs in a global statement in the same code block. Trying to delete an unbound name raises a NameError exception. [1]
名前とオブジェクトの関連付けをbindingとしているため, targetがidentifierの時, オブジェクト自体は削除されないことがわかる.
削除対象がattribute referenceまたはsubscriptionsの時
まず, attributerefの定義を確認する[2]
attributeref: primary "." identifierprimaryを評価した結果は, 属性を参照可能なオブジェクトである必要がある. 感覚的に, 大体のオブジェクトがattributerefであるとしていいだろう.
The primary must evaluate to an object of a type that supports attribute references, which most objects do. [2]
次に, subscriptionの定義を確認する[2]
subscription: primary '[' subscript ']'
subscript: single_subscript | tuple_subscript
single_subscript: proper_slice | assignment_expression
proper_slice: [expression] ":" [expression] [ ":" [expression] ]
tuple_subscript: ','.(single_subscript | starred_expression)+ [',']primaryにはリスト, 辞書などが該当する.
If the target is a subscription:
…
If the primary is a mutable sequence object (such as a list) ….
If the primary is a mapping object (such as a dictionary) …
If the target is a slicing: The primary expression should evaluate to a mutable sequence object (such as a list). … [1]
attributerefとsubscriptionに対するdelはprimary内での処理として行われる.
Deletion of attribute references and subscriptions is passed to the primary object involved; deletion of a slicing is in general equivalent to assignment of an empty slice of the right type (but even this is determined by the sliced object). [1]
実際の振る舞い
オブジェクトを参照する変数をdelする場合
変数が定義されていなかったのと同じ状況になる
class Obj:
def __init__(self):
pass
a = Obj()
del a
print(a)Traceback (most recent call last):
File "experiment2.py", line 7, in <module>
print(a)
^
NameError: name 'a' is not defined他の変数が同一オブジェクトを参照している場合, delした変数は定義されていなかった時と同じ状態になるが, オブジェクト自体は消えない.
class Obj:
def __init__(self):
pass
a = Obj()
b = a
del b
print(a)
print(b)<__main__.Obj object at 0x1006baa50>
Traceback (most recent call last):
File "experiment3.py", line 9, in <module>
print(b)
^
NameError: name 'b' is not definedオブジェクト内の属性をdelする場合
オブジェクトは残るが, delされた属性は存在しないことになる.
class Obj:
def __init__(self, x):
self.x = x
a = Obj(5)
del a.x
print(a)
print(a.x)<__main__.Obj object at 0x10746ea50>
Traceback (most recent call last):
File "experiment4.py", line 8, in <module>
print(a.x)
^^^
AttributeError: 'Obj' object has no attribute 'x'ガベージコレクション
ガベージコレクションの基本知識
ガベージコレクションは, 以下のどれかが満たされた時に行われる[5]
- システムの物理メモリが少ない時.
- プロセスに割り当てられたヒープで使用されているメモリが一定の閾値を超えた時
- GC.Collectメソッドが呼ばれた時.
ガベージコレクションは, 使わないオブジェクトを削除してヒープに空き容量を確保する. この時, ヒープ全体を捜査すると時間がかかってしまうため, あらかじめヒープを三つの世代に分割しておく(generation 0, generation 1, generation 2) [5]
新しいオブジェクトのための容量を開ける時, generation 0で不要なものを削除する. その後, generation 0で生き残ったものをgeneration 1に移動する. もし, generation 0で十分な容量が確保できなかったら, generation 1, generation 2と順番にガベージコレクションを行う. [5]
一連の動作はMark and Sweep Algorithmによって行われる(※ 他のアルゴリズムも存在するがここでは代表的なものとして紹介している)[6, 7]

このアルゴリズムはMark phaseとSweep phaseに分かれる.
Mark phsaeでは, DFSによって到達可能なオブジェクトのmark bitを1に変更する.
Sweep phaseでは, mark bitが1のものは0に戻し, mark bitが0のものはメモリを解放する.
Pythonのガベージコレクション
pythonはreference countを数える仕様をデフォルトで持っている. そして, reference countが0になった時, オブジェクトのメモリ割り当てを解放する.
All Python objects (even Python integers) have a type and a reference count.
…
When the last strong reference to an object is released (i.e. its reference count becomes zero), the object is deallocated. [3]
pythonのgarbage collectorは循環参照を解消するために用意されている. もし, 循環参照がない場合はgarbage collectorがなくても問題がない.
Since the collector supplements the reference counting already used in Python, you can disable the collector if you are sure your program does not create reference cycles. [4]
以下の例に示すように, どこからも参照されなくなったタイミングでオブジェクトは削除される. weakrefは参照されているかどうかカウントされない”弱い参照”と呼ばれるもの.
import weakref
class Obj:
def __init__(self):
self.next = None
a = Obj()
b = Obj()
c = Obj()
w = weakref.ref(b)
a.next = b
b.next = c
del b
print(w())
a.next = c
print(w())
<__main__.Obj object at 0x107679310>
None参考文献
[1] Python. python 3.14.3 Documentation >> The Python Language Reference >> 7. Simple statements https://docs.python.org/3/reference/simple_stmts.html
[2] Python. python 3.14.3 Documentation >> The Python Language Reference >> 6. Expressions https://docs.python.org/3/reference/expressions.html
[3] Python. python 3.14.3 Documentation >> Python/C API Reference Manual >> Introduction https://docs.python.org/3/c-api/intro.html
[4] Python. python 3.14.3 Documentation >> The Python Standard Library >> Python Runtime Services https://docs.python.org/3/library/gc.html
[5] Microsoft. Fundamentals of garbage collection https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals
[6] GeeksforGeeks. 2025. Mark-and-Sweep: Garbage Collection Algorithm https://www.geeksforgeeks.org/java/mark-and-sweep-garbage-collection-algorithm/
[7] Wikipedia. 2026. Tracing garbage collection. https://en.wikipedia.org/wiki/Tracing_garbage_collection
コメントを残す