Python 3 解释器在嵌入时是不是会泄漏内存?

Posted

技术标签:

【中文标题】Python 3 解释器在嵌入时是不是会泄漏内存?【英文标题】:Does the Python 3 interpreter leak memory when embedded?Python 3 解释器在嵌入时是否会泄漏内存? 【发布时间】:2012-02-06 14:33:43 【问题描述】:

This bug report 声明,截至 2007 年 6 月,Python 解释器在使用嵌入式 Python 解释器的 C/C++ 应用程序中调用 Py_Finalize 后不会清理所有分配的内存。建议在应用程序终止时调用一次 Py_Finalize。

This bug report 指出,截至 3.3 版和 2011 年 3 月,解释器仍会泄漏内存。

有人知道这个问题的当前状态吗?我很担心,因为我有一个应用程序,其中每个正在运行的实例都会多次调用解释器,并且我遇到了内存泄漏。

我已经在使用 boost::python 来处理引用计数,并且我清除了在两次运行之间运行 Python 程序创建的所有引用的全局字典。我有一些单例类 - 可能是这些问题吗?

这是一个易于处理的问题还是 Python 解释器中的错误?

【问题讨论】:

【参考方案1】:

您可以看到该错误(第一个,从 2007 年开始)已被 nnorwitz 以“wontfix”的形式关闭,他的帖子在错误报告中。

你为什么不止一次打电话给Py_Initialize/Py_Finalize? 为什么不做这样的事情(我有点混合 C 和 Python 方便):

/* startup */
Py_Initialize();

/* do whatever */
while (moreFiles()) 
    PyRun_SimpleString("execfile('%s')" % nextFile());
    /* do whatever */


/* shutdown */
Py_Finalize();

问题在于,大多数编写 Python 模块的人并不担心如果他们的模块被最终确定和重新初始化会发生什么,并且通常不关心在最终确定期间进行清理。模块作者知道进程退出时所有内存都会被释放,除此之外别无所求。

所以这不是一个真正的错误,它实际上是一千个错误——每个扩展模块一个。对于影响少数用户的错误来说,这是一项巨大的工作,其中大多数用户都有可行的解决方法。

您总是可以忽略对Py_Finalize 的调用,第二次调用Py_Initialize 是无操作的。这意味着当您第一次运行 Python 脚本时,您的应用程序将使用额外的内存,并且在您退出之前,额外的内存不会返回给操作系统。只要您仍然偶尔运行 Python 脚本,我就不会将其归类为泄漏。你的应用程序可能不是 Valgrind-clean,但它比像筛子一样泄漏要好。

如果您需要卸载(纯)Python 模块以避免内存泄漏,您可以这样做。只需从sys.modules 中删除它们即可。

Py_Finalize 的缺点: 如果您重复执行 Python 脚本,那么在它们之间运行Py_Finalize 没有多大意义。每次重新初始化时都必须重新加载所有模块;我的 Python 在启动时会加载 28 个模块。

补充说明:该错误不仅限于 Python。如果您尝试卸载和重新加载库,任何语言的大量库代码都会泄漏内存。许多库调用 C 代码,许多 C 程序员假设他们的库只加载一次,然后在进程退出时卸载。

【讨论】:

谢谢,虽然没有简单的解决方案有点令人失望。至少这验证了我目前的方法。 你想要完成什么? (通常,那个是可以解决的。) 我正在制作一个 Python IDE,它将重复执行 Python 脚本。每执行一次脚本,程序消耗的内存就会增加。我在应用程序启动时调用 Py_Initialize,从不调用 Py_Finalize(由 boost::python 调用)。这些脚本包含包括 PyOpenGL 和 PyQt 在内的库。我遇到了特别是在使用 QImage 时内存从未被释放的问题。 听起来像是 QImage 中的一个错误,但您是否考虑过在单独的进程中运行脚本?这就是 C 或 Java 等 IDE 的工作原理。 我还没有查看所有泄漏,但第一个泄漏不是来自表现不佳的模块。但是Py_Finalize itself!

以上是关于Python 3 解释器在嵌入时是不是会泄漏内存?的主要内容,如果未能解决你的问题,请参考以下文章

请解释一下“内存泄漏”,这个问题会有啥影响

当代码无法释放内存时,它是不是是 C 中的内存泄漏,但操作系统仍然会?

循环引用导致内存泄漏?

基本的内存泄漏的解释

解释 objgraph 数字:内存泄漏?

如何确定我的 android 应用程序是不是存在内存泄漏?