如何使用子进程强制Python释放内存?

2024-03-31

我正在阅读Python内存管理 http://deeplearning.net/software/theano/tutorial/python-memory-management.html并希望减少我的应用程序的内存占用。有人建议 https://stackoverflow.com/a/1316799 that 子流程 https://docs.python.org/2/library/subprocess.html将会大大缓解这个问题;但我很难概念化需要做什么。有人可以提供一个简单的例子来说明如何将其转变...

def my_function():
    x = range(1000000)
    y = copy.deepcopy(x)
    del x
    return y

@subprocess_witchcraft
def my_function_dispatcher(*args):
    return my_function()

...进入一个real不存储额外的“空闲列表”的子处理函数?

奖金问题:

这个“空闲列表”概念也适用于 python c 扩展吗?


优化建议的重要一点是确保my_function()仅在子流程中调用。这deepcopy and del无关紧要——一旦你在一个进程中创建了五百万个不同的整数,同时保留所有这些整数,游戏就结束了。即使您停止引用这些对象,Python 也会通过保留对 500 万个空整数对象大小字段的引用来释放它们,这些字段等待下一个想要创建 500 万个整数的函数重用。这是空闲列表在另一个答案中提到,它购买了整数和浮点数的快速分配和释放。对于 Python 来说,公平地说,这不是内存泄漏,因为内存肯定可用于进一步分配。但是,在进程结束之前,该内存不会返回到系统,也不会被重用于除了分配相同类型的数字之外的任何其他用途。

大多数程序不存在这个问题,因为大多数程序不会创建病态的巨大数字列表,释放它们,然后期望将该内存重用于其他对象。程序使用numpy也安全,因为numpy以紧密封装的本机格式存储其数组的数值数据。对于遵循这种使用模式的程序,缓解问题的方法是首先不要同时创建大量整数,至少不要在需要将内存返回给系统的进程中。目前尚不清楚您的具体用例是什么,但现实世界的解决方案可能需要的不仅仅是“魔术装饰器”。

这就是子进程的用武之地:如果数字列表是在另一个进程中创建的,则与该列表关联的所有内存(包括但不限于整数的存储)都会被释放并通过终止行为返回到系统子流程。当然,您必须设计程序,以便可以在子系统中创建和处理列表,而不需要传输所有这些数字。子进程可以接收创建数据集所需的信息,并且可以发回通过处理列表获得的信息。

为了说明原理,让我们升级您的示例,以便整个列表实际上需要存在 - 假设我们正在对排序算法进行基准测试。我们想要创建一个巨大的整数列表,对其进行排序,并可靠地释放与该列表关联的内存,以便下一个基准测试可以根据自己的需要分配内存,而不必担心 RAM 耗尽。为了生成子进程并进行通信,这使用了multiprocessing module:

# To run this, save it to a file that looks like a valid Python module, e.g.
# "foo.py" - multiprocessing requires being able to import the main module.
# Then run it with "python foo.py".

import multiprocessing, random, sys, os, time

def create_list(size):
    # utility function for clarity - runs in subprocess
    maxint = sys.maxint
    randrange = random.randrange
    return [randrange(maxint) for i in xrange(size)]

def run_test(state):
    # this function is run in a separate process
    size = state['list_size']
    print 'creating a list with %d random elements - this can take a while... ' % size,
    sys.stdout.flush()
    lst = create_list(size)
    print 'done'
    t0 = time.time()
    lst.sort()
    t1 = time.time()
    state['time'] = t1 - t0

if __name__ == '__main__':
    manager = multiprocessing.Manager()
    state = manager.dict(list_size=5*1000*1000)  # shared state
    p = multiprocessing.Process(target=run_test, args=(state,))
    p.start()
    p.join()
    print 'time to sort: %.3f' % state['time']
    print 'my PID is %d, sleeping for a minute...' % os.getpid()
    time.sleep(60)
    # at this point you can inspect the running process to see that it
    # does not consume excess memory

奖励答案

由于问题不清楚,因此很难回答奖励问题。 “空闲列表概念”正是这样一个概念,一个需要在常规 Python 分配器之上显式编码的实现策略。大多数 Python 类型都这样做not使用该分配策略,例如,它不用于使用创建的类的实例class陈述。实现空闲列表并不难,但它是相当高级的,并且很少在没有充分理由的情况下进行。如果某个扩展作者has选择对其类型之一使用空闲列表,可以预期他们意识到空闲列表提供的权衡 - 以一些额外空间为代价获得超快的分配/释放(对于空闲列表上的对象)以及空闲列表本身)并且无法将内存重用于其他用途。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用子进程强制Python释放内存? 的相关文章

随机推荐