从RAM中删除变量

6
在下面所示的函数中,我想在使用完x后清除其在内存中的值。
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

我尝试过以下方式并使用memory_profiler检查了内存使用情况,但都没起作用:

  • del x
  • x = None

我尝试的示例代码:

%%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命令:

python -m memory_profiler temp.py

结果(使用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
结果(使用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

编辑 全局删除和gc.collect()无效

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()

另外,我只是为了参考编写了这段代码, 在我的实际代码中,我会多次从一个函数调用到另一个函数,并且有时根据一些参数值和 x 的操作结果再次从内部调用相同的函数。

在每次调用之后,我想要在某些操作之后删除 x。


1
Python会在某个合适的时机回收被释放的内存。并不保证能立即恢复。这就是垃圾回收的本质。 - deceze
1
@deceze。除非使用“del”或“= None”,否则这里不会释放任何内存。 - Mad Physicist
你的最后一个分析器应该 del y,这样可以释放50%的内存。因为它持有对列表的引用。 - knh190
2个回答

8
假设你正在使用CPython(其他实现也可能如此),当某个对象的引用计数降至零时,垃圾回收将被触发。即使对象不会立即被垃圾回收,这也不是你看到结果的原因。原因是您无法对仍具有强引用的对象进行垃圾回收。 del 取消绑定当前命名空间中的名称,将引用计数减少一。它实际上不会删除任何内容。 del= 的相反操作,而不是 __new__
None 或任何其他对象分配给名称也会减少原始绑定的引用计数。唯一的区别是重新赋值会保留名称在命名空间中。
x = g([1] * 1000) 在全局模块命名空间中创建了一个对象。然后,在调用 f 并将该对象绑定到 f 的本地命名空间中的名称 x 之后,它就有了两个引用:一个在本地命名空间中,一个在全局命名空间中。
在正常情况下,只要您的模块没有被卸载,您的对象就不会消失。您还可以尝试在 f 中执行以下操作:
del x
del globals()['x']

另一种方法是使用临时变量避免在全局命名空间中赋值:

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

即使没有使用 del,你传递给 f 的临时变量也会在 f 返回后消失,因为它没有被其他地方引用。

任何一种方法都可能需要之后调用 gc.collect(),但在CPython中不应该这样做。


非常详细。谢谢分享! - Supratim Haldar
1
添加 del globals()['x'] 对我来说并没有减少内存,直到函数返回。不明白。它仍然被引用吗?还是因为垃圾回收没有触发? - knh190
我已经编辑了问题。编辑摘要:添加del globals()['x']不会减少内存。另外,如果x是从其他函数h传递而来而不是全局环境,我该怎么办? - Sam
尝试使用 del x, y,但在 f 中仍然引用了一个188MB的对象,检查 globalsvars 没有发现任何问题。 - knh190
@MadPhysicist 不是的。只有在函数返回后,这188 MB才会发生变化。 - knh190
显示剩余2条评论

0
Python的垃圾回收机制会在一段时间后自动释放未使用的内存。如果您想立即强制执行gc,可以在del之后尝试以下操作。
import gc
gc.collect()

在这种情况下没有帮助。此外,在CPython中,垃圾回收几乎是立即执行的。 - Mad Physicist
1
请问您能否分享一些详细信息,解释为什么在这种情况下它不起作用? - Supratim Haldar
感谢您详细的回答,@MadPhysicist,它很有帮助!然而,我并不能清楚地理解为什么在del之后运行gc.collect()将不起作用。我只是为了增进自己的理解和知识而提出这个问题,并非要争辩。 - Supratim Haldar
由于垃圾回收器不会删除正在使用的对象,即仍然被强引用的对象。当您在函数中调用“del x”时,全局命名空间中的引用不会消失。 - Mad Physicist
我明白了。谢谢! - Supratim Haldar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接