Garbage Collection in Python with Example

Table of Contents

Introduction

Garbage Collection is the process by which Python periodically destroys objects that are no longer in use from memory location and reclaims memory space.

Garbage Collection in Python can be controlled programatically by using gc module.

By default garbage collection is turned on in Python but you can turn it off. And even you can call it on your own and you can do your own clean up. Here is the Python code to disable, enable and manually collecting garbage:


# import garbage collector
import gc

# Disable
gc.disable()

# Enable
gc.enable()

# Collect
gc.collect()

But remember if you're turning it off then make sure that your code is not making any Circular References because it is easy to have circular references while programming. Which leads to memory leak.

In general gc module works just fine for Python version greater than 3.4 but if you're using Python version less than 3.4 there is a caveat. And this caveat is if any object in the circular references has destructor i.e. __del__() then destruction order is important and module gc cannot determine this order and object is marked as Uncollectable Object. As a result object is not cleaned.

Python Source Code: Garbage Collector

Following programs illustrate all concept related to reference counting, circular references & garabage collection.


# Importing related module
import ctypes
import gc

# Reference Counting
def count_references(id):
    return ctypes.c_long.from_address(id).value

# Looking object at garbage collection
def object_in_garbage(object_id):
    for obj in gc.get_objects():
        if id(obj) == object_id:
            return "Object is in garbage collection!"
    return "Object is not in garbage collection!"

# Following two classes creates circular references
class A:
    def __init__(self):
        self.var_a = B(self)
        print("A: {0}, var_a: {1}".format(id(self), id(self.var_a)))

class B:
    def __init__(self, obj):
        self.var_b = obj
        print("B: {0}, var_b: {1}".format(id(self), id(self.var_b)))

# Disabling garbage collection
gc.disable()

# Analyzing result
print()
print("------------------------------")
print("First look at these addresses:")
var = A()

# Storing id of object A and var_a
obj_a_id = id(var)
obj_b_id = id(var.var_a)


print()
print("------------------------------")
print("Verifying by displaying id:")
print('Object A:',obj_a_id)
print('Object B:', obj_b_id)

print()
print("------------------------------")
print("Displaying reference count for object A and object B:")
ref_count_a = count_references(obj_a_id)
ref_count_b = count_references(obj_b_id)
print("Object A reference count: ", ref_count_a)
print("Object B reference count: ", ref_count_b)

# Collecting var
var = None

print()
print("------------------------------")
print("Displaying reference count for object A and object B:\n(After collecting var)")
ref_count_a = count_references(obj_a_id)
ref_count_b = count_references(obj_b_id)
print("Object A reference count: ", ref_count_a)
print("Object B reference count: ", ref_count_b)

# Verifying existance of object
print()
print("BEFORE COLLECTING GARBAGE")
print("------------------------------")
print(object_in_garbage(obj_a_id))
print(object_in_garbage(obj_b_id))

# Manually collecting garbage
gc.collect()

# Verifying existance of object after collecting
print()
print("------------------------------")
print("AFTER COLLECTING GARBAGE")
print(object_in_garbage(obj_a_id))
print(object_in_garbage(obj_b_id))

print()
print("------------------------------")
print("Displaying reference count for object A and object B:\n(After Collecting)")
ref_count_a = count_references(obj_a_id)
ref_count_b = count_references(obj_b_id)
print("Object A reference count: ", ref_count_a)
print("Object B reference count: ", ref_count_b)

# Finally enable garbage collector
gc.enable()

Output

------------------------------
First look at these addresses:
B: 2040345416712, var_b: 2040345416776
A: 2040345416776, var_a: 2040345416712

------------------------------
Verifying by displaying id:
Object A: 2040345416776
Object B: 2040345416712

------------------------------
Displaying reference count for object A and object B:
Object A reference count:  2
Object B reference count:  1

------------------------------
Displaying reference count for object A and object B:
(After collecting var)
Object A reference count:  1
Object B reference count:  1

BEFORE COLLECTING GARBAGE
------------------------------
Object is in garbage collection!
Object is in garbage collection!

------------------------------
AFTER COLLECTING GARBAGE
Object is not in garbage collection!
Object is not in garbage collection!

------------------------------
Displaying reference count for object A and object B:
(After Collecting)
Object A reference count:  0
Object B reference count:  0