调用Python函数后,RAM不会被释放

时间:2018-03-12 15:32:16

标签: python memory memory-management memory-leaks heap-memory

我使用内部Python库进行科学计算。我需要连续复制一个对象,修改它,然后删除它。对象很大,导致我的机器在几个周期后耗尽内存。

第一个问题是我使用python' del来删除对象,这显然只取消引用对象,而不是释放RAM。

第二个问题是即使我将整个进程封装在一个函数中,在调用该函数之后,RAM仍然没有被释放。这是一个代码片段,可以更好地解释这个问题。

ws = op.core.Workspace()
net = op.network.Cubic(shape=[100,100,100], spacing=1e-6)
proj = net.project

def f():
    for i in range(5):
        clone = ws.copy_project(proj)
        result = do_something_with(clone)
        del clone

f()
gc.collect()

>>> ws
{'sim_01': [<openpnm.network.Cubic object at 0x7fed1c417780>],
 'sim_02': [<openpnm.network.Cubic object at 0x7fed1c417888>],
 'sim_03': [<openpnm.network.Cubic object at 0x7fed1c417938>],
 'sim_04': [<openpnm.network.Cubic object at 0x7fed1c417990>],
 'sim_05': [<openpnm.network.Cubic object at 0x7fed1c4179e8>],
 'sim_06': [<openpnm.network.Cubic object at 0x7fed1c417a40>]}

我的问题是如何完全删除Python对象?

谢谢!

PS。在代码段中,每次调用ws.copy_project时,proj的副本都会存储在ws字典中。

1 个答案:

答案 0 :(得分:0)

这里有一些非常聪明的蟒蛇人。他们可能会告诉你更好的方法来保持你的记忆清晰,但我之前使用过漏洞库,并找到一种(迄今为止)万无一失的方法来保证你的内存在使用后被清除:在另一个进程中执行内存占用

要做到这一点,您需要安排一种简单的方法,使您的长计算可以单独执行。我通过在我现有的python脚本中添加特殊标志来完成此操作,该脚本告诉它只是运行该函数;您可能会发现将该函数放在单独的.py文件中更容易,例如:

do_something_with.py

import sys
def do_something_with(i)
    # Your example is still too vague.  Clearly, something differentiates
    # each do_something_with, otherwise you're just taking the
    # same inputs 5 times over.
    # Whatever the difference is, pass it in as an argument to the function

    ws = op.core.Workspace()
    net = op.network.Cubic(shape=[100,100,100], spacing=1e-6)
    proj = net.project

    # You may not even need to clone anymore?
    clone = ws.copy_project(proj)
    result = do_something_with(clone)

# Whatever arg(s) you need to get to the function, just pass it in on the command line
if __name__ == "__main__":
    sys.exit(do_something_with(sys.args[1:]))

您可以使用任何处理子进程的python工具来执行此操作。在python 3.5+中,推荐的方法是subprocess.run。您可以将更大的功能更改为以下内容:

import subprocess

invoke_do_something(i):
    completed_args = subprocess.run(["python", "do_something_with.py", str(i)], check=False)
    return completed_args.returncode

results = map(invoke_do_something, range(5))

你显然需要根据自己的情况定制它,但是通过在子进程中运行,你可以保证不必担心内存被清理。作为额外的好处,您可以使用multiprocess.Pool.map一次使用多个处理器。 (我故意将其编码为使用map来简化这样的转换。如果您愿意,您仍然可以使用for循环,然后您不需要invoke...函数。)多处理可以加快处理速度,但是因为你已经担心内存,几乎肯定是一个坏主意 - 有了大量内存占用的多个进程,你的系统本身可能会很快耗尽内存并终止你的进程。

你的例子相当模糊,所以我写的很高。如果你需要,我可以回答一些问题。