嵌入时Python 3解释器会泄漏内存吗?

5 投票
1 回答
2539 浏览
提问于 2025-04-17 09:54

这个错误报告提到,从2007年6月开始,Python解释器在C/C++应用程序中嵌入Python解释器后,调用Py_Finalize时不会清理所有分配的内存。建议在应用程序结束时只调用一次Py_Finalize。

这个错误报告提到,从3.3版本和2011年3月开始,解释器仍然存在内存泄漏的问题。

有没有人知道这个问题现在的情况?我很担心,因为我有一个应用程序在每次运行实例中多次调用解释器,并且我遇到了内存泄漏。

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

这个问题能解决吗,还是说这是Python解释器的一个错误?

1 个回答

6

你可以看到,2007年的那个bug被nnorwitz关闭了,标记为“不会修复”,他的帖子在这个bug报告里。

你为什么要多次调用 Py_Initialize/Py_Finalize 呢? 为什么不试试这样做(我为了方便,把C和Python混在一起了):

/* startup */
Py_Initialize();

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

/* shutdown */
Py_Finalize();

问题是,大多数写Python模块的人并不关心他们的模块在被结束和重新初始化时会发生什么,通常也不在乎在结束时是否要清理。模块的作者知道,当进程退出时,所有内存都会被释放,所以他们也就不再多想了。

所以这其实不是一个bug,而是成千上万个bug——每个扩展模块都有一个。这对影响少数用户的bug来说,工作量是巨大的,而大多数用户都有可行的解决办法。

你可以选择不调用 Py_Finalize,第二次调用 Py_Initialize 不会有任何效果。这意味着当你第一次运行Python脚本时,你的应用会使用更多的内存,而这些额外的内存在你退出之前不会返回给操作系统。只要你偶尔还在运行Python脚本,我不会把它算作内存泄漏。你的应用可能不够干净,但总比漏得像筛子要好。

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

Py_Finalize 的缺点: 如果你在重复执行Python脚本,频繁调用 Py_Finalize 就没什么意义了。每次重新初始化时,你都得重新加载所有模块;我启动时就要加载28个模块。

额外评论: 这个bug并不仅限于Python。任何语言的库代码在尝试卸载和重新加载库时,都会出现内存泄漏的问题。很多库会调用C代码,很多C程序员认为他们的库只会加载一次,并在进程退出时卸载。

撰写回答