Boost-Python2移植到Boost-Python3后程序退出时崩溃问题
Boost-Python3嵌入程序退出崩溃问题排查
问题场景
将程序从Boost-Python2移植到Boost-Python3时,发现嵌入Python3的Boost程序退出时崩溃,但相同代码基于Python2.7构建可正常运行。可复现的示例代码如下:
#include <boost/python.hpp> #include <stdio.h> int main() { Py_InitializeEx(0); boost::python::object modMath = boost::python::import("math"); boost::python::object cosFunc = modMath.attr("cos"); Py_Finalize(); }
Python3.x环境下的回溯信息:
Program received signal SIGSEGV, Segmentation fault. PyObject_GC_Del (op=0x7ffff6f134f0) at ../Modules/gcmodule.c:2313 2313 ../Modules/gcmodule.c: Нет такого файла или каталога. (gdb) bt #0 PyObject_GC_Del (op=0x7ffff6f134f0) at ../Modules/gcmodule.c:2313 #1 0x0000555555555366 in _Py_DECREF (op=0x7ffff6f134f0) at /usr/include/python3.9/object.h:430 #2 0x0000555555555469 in boost::python::api::object_base::~object_base (this=0x7fffffffde78, __in_chrg=<optimized out>) at /usr/include/boost/python/object_core.hpp:423 #3 0x00005555555553a8 in boost::python::api::object::~object (this=0x7fffffffde78, __in_chrg=<optimized out>) at /usr/include/boost/python/object_core.hpp:238 #4 0x0000555555555244 in main () at test3x_tb.cpp:12
原因分析
Python3与Python2在Py_Finalize()的行为上存在关键差异:
- Python2中,
Py_Finalize()后仍允许部分不规范的Python对象操作,不会立即触发崩溃 - Python3中,
Py_Finalize()会彻底销毁Python运行时环境,释放所有相关内存资源
示例代码中,modMath和cosFunc是栈上的boost::python::object对象,它们的析构时机是main()函数结束时——此时Py_Finalize()已经执行完毕,Python运行时已被销毁。当Boost Python的对象析构函数调用Py_DECREF时,会访问已经被释放的内存空间,直接触发段错误。
解决方法
核心思路是让所有Boost Python对象在Py_Finalize()之前完成析构,具体有两种实现方式:
方案1:使用局部作用域限制对象生命周期
通过添加代码块,将Python相关操作包裹起来,确保modMath和cosFunc在Py_Finalize()调用前就被销毁:
#include <boost/python.hpp> #include <stdio.h> int main() { Py_InitializeEx(0); { boost::python::object modMath = boost::python::import("math"); boost::python::object cosFunc = modMath.attr("cos"); // 在这里执行需要Python对象的操作 } // 作用域结束,modMath和cosFunc自动析构 Py_Finalize(); }
该方案符合C++的RAII原则,代码简洁安全,优先推荐。
方案2:动态分配对象并手动释放
如果无法使用局部作用域,可以用new动态分配boost::python::object,在Py_Finalize()前手动delete:
#include <boost/python.hpp> #include <stdio.h> int main() { Py_InitializeEx(0); boost::python::object* modMath = new boost::python::object(boost::python::import("math")); boost::python::object* cosFunc = new boost::python::object((*modMath).attr("cos")); // 执行需要Python对象的操作 delete cosFunc; delete modMath; // 手动释放对象,确保在Py_Finalize前完成 Py_Finalize(); }
内容的提问来源于stack exchange,提问作者dhyan.nataraj
相关产品推荐
相关产品推荐

