Post

python GC(Garbage Collector)

python GC(Garbage Collector)

This post was migrated from Tistory. You can find the original here.

Python Garbage Collector

Basically, objects get freed via reference counting, and on top of that, Generational Garbage Collection seems to kick in whenever a generation’s threshold is crossed.

Reference Counting

When an object’s reference count hits 0, it gets garbage collected.

Generational Garbage Collection

This is the GC mechanism that solves the problem reference counting can’t handle on its own: circular references, where the count never reaches 0.

It’s built around the concepts of generations and thresholds.

1
2
3
import gc

print(gc.get_threshold()) #(700, 10, 10)

The tuple represents generation 0, generation 1, and generation 2, in that order.

As long as the number of generation-0 objects stays under 700 (the threshold), garbage — including circular references — just sits allocated in memory.

Once the threshold is exceeded, the generational GC runs, and any objects that survive get promoted to the next generation.

The threshold for generation 1 is 700*10, and for generation 2 it’s 700*10*10.

Generational GC runs by fully pausing the application (stop-the-world).

Because of that, the thresholds are configurable, which gives you a tradeoff:

use more memory and you can space out GC cycles further apart,

or run GC cycles more frequently and use less memory.

+ Extra

1
2
3
4
5
6
7
8
9
10
11
class Test:
    def __init__(self, i) -> None:
        print(gc.get_count())
        print(f"hi {i} id:{id(i)}")
    
    def __del__(self):
        print(f"bye {i} id:{id(i)}")

for i in range(3):
    test = Test(i)
    # del(test)
1
2
3
4
5
6
7
8
9
(237, 1, 1)
hi 0 id:140718906091280
(238, 1, 1)
hi 1 id:140718906091312
bye 1 id:140718906091312
(238, 1, 1)
hi 2 id:140718906091344
bye 2 id:140718906091344
bye 2 id:140718906091344

The first object created doesn’t get destroyed automatically…? And for the last one, the destructor ran twice. (Not sure why yet.)

1
2
3
4
5
6
7
8
9
(237, 1, 1)
hi 0 id:140718906091280
bye 0 id:140718906091280
(237, 1, 1)
hi 1 id:140718906091312
bye 1 id:140718906091312
(237, 1, 1)
hi 2 id:140718906091344
bye 2 id:140718906091344

If you explicitly call del at the end of each loop iteration, you get the expected result.

References

https://medium.com/dmsfordsm/garbage-collection-in-python-777916fd3189

https://devbull.xyz/python-garbace-collection/

This post is licensed under CC BY-NC 4.0 by the author.