You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++实现Python扩展出现Segmentation Fault问题求助

问题分析与解决方案

核心原因

你遇到的Segmentation Fault本质是引用计数操作违规:要么是对已被Python回收的对象调用了Py_DecRef,要么是释放了并非由你持有引用的对象(比如Python内置常量、其他模块生成的对象,这类对象的引用计数不该由你手动修改)。注释掉Py_DecRef时,虽然会存在内存泄漏,但避免了非法内存访问,所以程序暂时能正常运行。

关键排查方向

1. 核对Py_DecRef的对象归属

  • 如果你是通过PyTuple_New/PyList_New等函数自行创建的对象:
    • 若该对象已被添加到外层容器(比如嵌套元组/列表),容器会自动持有它的引用,此时你无需额外调用Py_DecRef——否则会导致对象引用计数提前归零被回收,后续容器访问该对象时就会触发段错误。
      典型错误示例:
    PyObject* inner_tuple = PyTuple_New(2);
    PyTuple_SetItem(inner_tuple, 0, PyLong_FromLong(1));
    PyTuple_SetItem(inner_tuple, 1, PyLong_FromLong(2));
    PyObject* outer_list = PyList_New(0);
    PyList_Append(outer_list, inner_tuple);
    Py_DecRef(inner_tuple); // 错误:outer_list已持有inner_tuple的引用,此处减引用会导致对象提前被回收
    
  • 若对象是PyLong_FromLong这类函数返回的新对象:
    这类函数返回的对象引用计数为1,如果你将其加入容器,容器会自动执行Py_INCREF,此时你需要调用Py_DecRef释放自己持有的那份引用;但如果是直接将对象返回给Python解释器,无需手动调用Py_DecRef,因为调用方会负责处理。

2. 区分原始内存与Python对象

PyMem_RawMalloc分配的是原始内存块,不属于Python垃圾回收体系,绝对不能对这类内存调用Py_DecRef——如果你的代码中误将原始内存块当作PyObject*调用Py_DecRef,必然触发段错误。确保只有真正的PyObject*类型对象才会执行Py_INCREF/Py_DecRef操作。

3. 实用调试手段

  • 使用gdb定位崩溃点:运行gdb python,输入run your_test_script.py,程序崩溃后输入bt查看调用栈,直接定位到触发崩溃的Py_DecRef代码行,确认对应的对象问题。
  • 启用Python调试模式:编译扩展时添加-DPy_DEBUG编译选项,运行时会触发更多断言检查,快速揪出非法的引用计数操作。

修复步骤

  1. 梳理所有PyObject*对象的生命周期:
    • 标记每个对象是自行创建还是外部传入
    • 记录对象被添加到容器或返回给Python的时机,确保引用计数操作匹配
  2. 逐一校验Py_DecRef操作:
    • 确认对象确实是你持有额外引用的(比如创建后未被容器接管,或你手动执行过Py_INCREF)
    • 排除对Python内置常量(如Py_None)调用Py_DecRef的情况
  3. 替换错误的内存分配方式:如果用PyMem_RawMalloc是为了创建Python对象,改用PyObject_New或对应类型的创建函数(如PyTuple_New),不要手动管理原始内存。

内容的提问来源于stack exchange,提问作者the drugs don't work

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 21:43:14