【问题标题】:RAM is not freed after a Python function is invoked调用 Python 函数后不释放 RAM
【发布时间】:2018-08-20 16:40:11
【问题描述】:

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

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

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

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 对象?

谢谢!

附言。在代码sn-p中,每次调用ws.copy_project,都会在ws字典中保存一份proj的副本。

【问题讨论】:

  • 我可以对您的代码进行一些澄清。您是说proj 很大并导致内存问题,对吧?但是您在f 中显示的循环只是让您将proj 的十个副本添加到列表中。你有什么东西可以作用于数据并且可以给你一个更小的结果,或者可以将大数据存储在一个文件中?鉴于其中任何一个,我都可以提出解决方案。刚刚给出“这个很大,我想要十个”,我帮不了你。 (虽然简化的代码对我们很有帮助,但这似乎被简化到充满错误的地步。)
  • @ScottMermelstein 感谢您的回复。我编辑了这个问题。澄清一下,问题是即使我在每次迭代后删除clone,RAM 也不会被释放。

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


【解决方案1】:

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

为此,您需要安排一种简单的方法来使您的长计算可以单独执行。我通过在我现有的 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... 函数。)多处理可以加快你的处理速度,但是因为你'已经担心内存问题,几乎可以肯定是个坏主意 - 如果有多个进程占用大量内存,您的系统本身可能会很快耗尽内存并杀死您的进程。

您的示例相当模糊,因此我已在较高级别上编写了此示例。如果您需要,我可以回答一些问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-04
    • 1970-01-01
    • 1970-01-01
    • 2013-10-28
    • 2020-10-07
    • 2023-02-01
    • 1970-01-01
    相关资源
    最近更新 更多