Delete variable from RAM

Viewed 840

In the function shown below, I want to clear the value of x from memory after using it.

def f(x, *args):
   # do something
   y = g(x) # here i want to use x as argument and clear value of x from ram
   # do something

I have tried following method and checked memory usage using memory_profiler but nothing worked:

  • del x
  • x = None

Sample code on which I tried:

%%file temp.py
import lorem

@profile
def f(x, use_none=True):
  # do something
  y = g(x)
  if use_none:
    x = None
  else:
    del x
  # do something


def g(x):
  n = len(x)
  return [lorem.paragraph() * i for i in range(n)]

if __name__ == '__main__':
  x = g([1] * 1000)
  # f(x, True)
  f(x, False)

memory_profiler command:

python -m memory_profiler temp.py

Result (using None):

Filename: temp.py

Line #    Mem usage    Increment   Line Contents
================================================
     3  187.387 MiB  187.387 MiB   @profile
     4                             def f(x, use_none=True):
     5                               # do something
     6  340.527 MiB  153.141 MiB     y = g(x)
     7  340.527 MiB    0.000 MiB     if use_none:
     8  340.527 MiB    0.000 MiB       x = None
     9                               else:
    10                                 del x

Result (using del):

Filename: temp.py

Line #    Mem usage    Increment   Line Contents
================================================
     3  186.723 MiB  186.723 MiB   @profile
     4                             def f(x, use_none=True):
     5                               # do something
     6  338.832 MiB  152.109 MiB     y = g(x)
     7  338.832 MiB    0.000 MiB     if use_none:
     8                                 x = None
     9                               else:
    10  338.832 MiB    0.000 MiB       del x

Edit Deleting from global and gc.collect() is not working

Filename: temp.py

Line #    Mem usage    Increment   Line Contents
================================================
     4  188.953 MiB  188.953 MiB   @profile
     5                             def f(x, use_none=True):
     6                               # do something
     7  342.352 MiB  153.398 MiB     y = g(x)
     8  342.352 MiB    0.000 MiB     if use_none:
     9                                 x = None
    10                                 globals()['x'] = None
    11                                 gc.collect()
    12                               else:
    13  342.352 MiB    0.000 MiB       del x
    14  342.352 MiB    0.000 MiB       del globals()['x']
    15  342.352 MiB    0.000 MiB       gc.collect()

Also, I write this code just for reference, In my actual code, I am calling from function to another function multiple time, and sometimes call same function from inside, based on some parameter value and value of x after some operation.

After every call, I want to delete x after some operation.

2 Answers

Assuming you are using CPython (possibly other implementations too), garbage collection is triggered when the reference count for an object drops to zero. Even if the object were not garbage collected immediately, that wouldn't be the reason you are seeing your result. The reason is that you can't garbage collect objects that still have strong references to them.

del unbinds the name in your current namespace, decreasing the reference count by one. It does not actually delete anything. del is an inverse to =, not __new__.

Assigning None, or any other object to the name also decrements the reference count of the original binding. The only difference is that reassignment keeps the name in the namespace.

The line x = g([1] * 1000) creates an object in the global module namespace. You then call f and bind that object to the name x in f's local namespace. At that point, there are two references to it: one in the local namesapace, and one in the global.

Your object won't disappear under normal circumstances until your module is unloaded. You can also try something like the following in f:

del x
del globals()['x']

Another way is to use a temporary variable to avoid assigning in the global namespace:

f(g([1] * 1000), False)

The temporary variable you pass to f will disappear as soon as f returns, even without del, since it isn't referenced elsewhere.

Either option might require a call to gc.collect() after, but shouldn't in CPython.

Python garbage collection will automatically deallocate unused memory after a while. If you want to enforce gc immediately, the following can be tried after del.

import gc
gc.collect()
Related