I'm playing around with CPython's garbage collector (GC), or rather the part that collects reference cycles. I'm confused why the following activity triggers it. (If it matters, I'm doing the following demo with IPython 7.22.0 (command shell), Python 3.8.8, Spyder 4.2.5 (IDE), macOS.
First I make it so that every time the GC runs, statistics are printed about the collected generation. I'm only doing this to see when collection happens.
import gc
gc.set_debug(gc.DEBUG_STATS)
Now I assign 0 to a variable x repeatedly. Every 9 times or so, the GC runs.
x = 0 # run repeatedly by hand
If I do this in a function, the GC still runs every 9 calls:
def f():
x = 0
f() # run repeatedly by hand
According to the Python 3.9.6 documentation of the gc module's is_tracked function, the GC does not track "atomic types," which includes the built-in number types. So if I'm only allocating objects that cannot have reference cycles and aren't tracked by the GC, why is the GC being triggered? What objects are being created that I don't know about?
UPDATE: This behavior does not happen in a Python process opened in the terminal with python -i (version 3.8.8, Clang 10.0.0). Running x=5 or x = [i for i in range(1000)] dozens of times does not trigger the GC, but running x = [[i] for i in range(1000)] just once triggers the GC. This is more in line with the documentation. I'm guessing IPython is allocating hidden objects that are tracked by the GC.