-1

The following code...

t = (1,2)
print(id(t))
del t
print(id((1,2))

Only deletes the name t (as expected), and the output prints the same id as before

Output

1324781299264
1324781299264

This would apply to all immutable types, which means the memory for the same isn't actually de-allocated or perhaps would eventually be, by the garbage collector. But is there any way to force de-allocate memory for an immutable object in Python?

Henlo Wald
  • 37
  • 6
  • 2
    Why would you need to do this, if it could be done? – Scott Hunter Jul 15 '21 at 16:03
  • If there ends up being an answer to this, I'm sure it's going to be implementation-specific. The IDs of Python objects are an implementation detail. I'm assuming you're using CPython but it's worth specifying anyway in a case like this I think. – Random Davis Jul 15 '21 at 16:05
  • 2
    You are misinterpreting what you see. The memory location gets reused *because it is free*, not because it is retained. ``(1,2)`` just happens to fit into a ``(1,2)`` shaped hole. – MisterMiyagi Jul 15 '21 at 16:05
  • @RandomDavis Yes, it is CPython the default implementation. – Henlo Wald Jul 15 '21 at 16:07
  • For example, on my machine ``print(*(id((i, i+1)) for i in range(5)))`` reports the same memory location 5 times, because every tuple ``(i, i+1)`` fits exactly into the space left over by its predecessor. Obviously, that's something completely different than Python keeping all objects around indefinitely. – MisterMiyagi Jul 15 '21 at 16:08
  • Note that there are various ways for Python to retain a tuple – e.g. because it was deduplicated during compilation and is used in several places, or [retained for efficient recycling](https://stackoverflow.com/questions/14135542/how-is-tuple-implemented-in-cpython) (both of these may apply to your case) – but in all these cases Python has a good reason for keeping them around. If you forcefully deallocate the memory you are effectively ripping a hole into the interpreter state. – MisterMiyagi Jul 15 '21 at 16:18
  • Anyway, what platform are you on? Freeing memory the naive way is platform dependent. – MisterMiyagi Jul 15 '21 at 16:21
  • Seems like my theory on immutable objects was wrong... I think Python doesn't always re-use immutable objects...and this rule only applies to string to an extent. – Henlo Wald Jul 15 '21 at 16:27
  • I am on WIndows. – Henlo Wald Jul 15 '21 at 16:27

1 Answers1

2

You can forcefully deallocate an object by using the C memory de/allocation functions, for example via ctypes.

t = (1, 2)
print(id(t))
print(id((1, 2)))
pyc = ctypes.CDLL(None)  # system dependent – should work on Unix
pyc.PyMem_Free(id(t))
print(id((1, 2)))

Notably, on "Python 3.9.5 (default, May 4 2021, 03:29:30) [Clang 11.0.0 (clang-1100.0.33.17)] on darwin" (likely any other recent CPython) this causes a segfault – we just blew a hole into the memory managed by the interpreter, and removed an object it was still expecting to use.

$ python so_testbed.py
4493301568
4493301568
[1]    47059 segmentation fault  python so_testbed.py

Keep in mind that the interpreter has a reason to keep things around.

For example, literals used in the same compilation unit may be deduplicated

# so_testbed.py
def foo():
    t = (1, 2)
    print(id(t))       # 4434270720
    print(id((1, 2)))  # 4434270720
foo()

whereas they are distinct when part of separate code, such as separate input statements in the shell

>>> t = (1, 2)
>>> print(id(t))
4484905536
>>> print(id((1, 2)))
4485748416

These optimisation have been carefully chosen to conservatively improve code execution, and are deeply ingrained in the interpreter – this includes not being harmful in practice. You cannot easily switch them off, nor should you.

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119