如果我在命名空间中导入Python模块,我可以可靠地取消导入吗?

时间:2011-05-31 01:19:33

标签: python

基本上,我有一个漫长的运行过程,我希望能够通过gc取消模块和恢复内存。我已经阅读了有关删除模块How do I unload (reload) a Python module?的内容,似乎仍然存在阻止gc的悬空引用。

但是,如果我仅在命名空间内导入和使用该模块,该怎么办?换句话说,就像这样:

ns = {}
exec somecode in ns

然后我将清理命名空间内的sys.modules并通过删除命名空间本身来完成。

这会释放内存以便在CPython中重用吗?

如果没有,那么可以使用ctypes访问Python C API的某些部分来实现这一目标吗?

最终结果的重要部分是释放内存,以便运行数周或数月的进程可以在不重新加载模块的情况下可靠地取消导入模块。当然,在该时间段内,任何给定模块完全可能被加载和卸载多次。我假设一个模块在加载时可以创建大量对象,并且正常清理(sys.modules和del)会将这些对象永久保留在内存中。

Jochen:是的,我可以通过多种方式解决这个问题,但我有兴趣探索Python的极限。

2 个答案:

答案 0 :(得分:3)

如果您真正想要的是避免内存泄漏,最好的办法是安排以正常方式导入模块一次,sys.modules处于通常状态。无论稍后导入模块多少次,它都不会占用更多内存,因为导入机器将继续返回相同的模块。

如果由于某种原因,这仍然不合适,那么说模块是动态创建的,只需要使用一次,exec certainly isn't the solution。您应该考虑使用替代执行模型,可能会分支新流程。

答案 1 :(得分:3)

要取消导入模块,您需要确保已删除对模块的所有引用。这意味着您必须从导入它的所有模块中删除引用,从sys.modules删除引用,删除对该模块中定义的任何函数或类的任何引用,并删除对作为在模块。

在几乎所有情况下,这都需要更多的努力来检索相对较少的内存量。如果您真的想尝试这个,那么gc.get_referrers()可能会有用,因为您可以删除模块中除了一个已知引用之外的所有引用,然后追溯以找到仍然引用它的内容。