I am currently working on an example to understand Python memory management and garbage collection. In my example, I create a variable (x = 10
), collect its id, delete it, initiate garbage collector and check if I can still access object in heap by its id (using ctypes).
I think it would return 0 or an error but surprisingly I can still access the object and I don't understand why. Could you help me to understand this case?
A big thank you in advance,
import ctypes
x = 10
id_1st_obj = id(x)
del(x)
gc.collect()
print(ctypes.cast(id_1st_obj, ctypes.py_object).value)
Few things come into play, but here's a simple counterexample:
import ctypes
import gc
x = 1
for _ in range(10):
x += x
id_1st_obj = id(x)
del x
gc.collect()
print(ctypes.cast(id_1st_obj, ctypes.py_object).value)
If you comment del x
, you get 1024. If you don't, we get some "random" number.
The reason you're seeing the old value is simple - as @jonrsharpe said - small integers ([-4, 255]
) are interned, meaning Python keeps only a single copy of them, and whenever you would reference an integer of that value, it gets pointed at this single copy of the object. So even if you don't have any explicit references to 10
in your code, Python still stores that single copy for interning.
Same might happen with "constant" variables, meaning ones that can be optimised away in the bytecode. That's why even if you change x = 10
to x = 1000
in your code you might still see the same behaviour (might, as this will not happen for e.g. in interactive session, as the step with optimising constants does not happen there).