繁体   English   中英

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

[英]Can I reliably unimport a Python module if I import it in a namespace?

基本上,我有一个长时间运行的过程,我希望能够通过 gc 取消导入模块并恢复 memory。 我已阅读有关删除模块的信息 如何卸载(重新加载)Python 模块? 并且似乎仍然存在阻止 gc 的悬空引用。

但是,如果我只在命名空间内导入和使用模块怎么办。 换句话说,是这样的:

ns = {}
exec somecode in ns

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

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

如果没有,那么是否可以使用 ctypes 访问 Python C API 的某些部分来完成此操作?

最终结果的重要部分是 memory 已发布,因此运行数周或数月的进程可以可靠地卸载模块而无需重新加载它。 当然,任何给定的模块完全有可能在该时间段内多次加载和卸载。 我假设一个模块在加载时可以创建大量对象,并且通常的清理(sys.modules 和 del)会将这些对象永远留在 memory 中。

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

如果您真正想要的是避免 memory 泄漏,那么您最好的选择可能是安排一次导入模块,以正常方式,在通常的 state 中使用sys.modules 无论模块稍后导入多少次,都不会再占用 memory,因为导入机器只会继续返回相同的模块。

如果由于某种原因,这仍然不适合,比如模块正在动态创建并且只需要使用一次,那么exec肯定不是解决方案 您应该考虑使用替代执行 model,可能会分叉新进程。

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

在几乎所有情况下,这比检索相对少量的 memory 付出的努力更多。 如果您真的想尝试这个,那么gc.get_referrers()可能会很有用,因为您可以删除除一个已知引用模块之外的所有引用,然后回溯以查找仍然引用它的其他内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM