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

PyPy自定义C++扩展抛出Python异常时内存泄漏求助

PyPy中C++扩展自定义类型抛异常导致内存泄漏的问题解决

问题描述

我正在编写支持CPython和PyPy的C++扩展,其中包含带调用接口的自定义类型。但在PyPy中抛出Python异常时出现内存泄漏,CPython下则无此问题。已隔离出泄漏代码,构建后可通过python test.py或pypy test.py验证。

C++扩展类代码

struct custom_function {
    PyObject_HEAD
};

PyObject* custom_call(PyObject *self, PyObject *args, PyObject *kwargs) {
    std::cout << "Calling custom function with except, simpler" << std::endl;

    PyErr_SetString(PyExc_SystemError, "Fancier exception for custom fancy func");
    return nullptr;
};

PyTypeObject custom_function_type = {
    PyVarObject_HEAD_INIT(NULL, 0)
    .tp_name = "custom_function",
    .tp_basicsize = sizeof(custom_function),
    .tp_itemsize = 0,
    .tp_call = custom_call,
    .tp_flags = Py_TPFLAGS_DEFAULT,
    .tp_doc = PyDoc_STR("Custom function type"),
    .tp_new = PyType_GenericNew,
};

内存泄漏检测代码

import helloworld as m
import gc
import weakref

class ExampleClass:
    def __init__(self):
        pass

def simple_test(f):
    it = ExampleClass()
    a = weakref.ref(it)
    try:
        f(it)
    except Exception as e:
        print("Got exception!", e)
        del e

    assert a() is not None
    del it
    gc.collect()
    assert a() is None

simple_test(m.custom_fancy_func)

问题原因

PyPy的对象模型与CPython存在差异:当自定义类型的tp_call方法抛出异常(通过PyErr_SetString设置并返回nullptr)时,PyPy不会自动清理传入的args和kwargs参数的引用计数。而CPython会在异常处理逻辑中自动释放这些参数的引用,导致PyPy中ExampleClass实例的引用计数无法归零,最终引发内存泄漏。

解决方案

在custom_call方法抛出异常返回nullptr前,必须手动减少args和kwargs的引用计数。修改后的代码如下:

PyObject* custom_call(PyObject *self, PyObject *args, PyObject *kwargs) {
    std::cout << "Calling custom function with except, simpler" << std::endl;

    PyErr_SetString(PyExc_SystemError, "Fancier exception for custom fancy func");
    // 手动释放参数引用,Py_XDECREF在参数为NULL时不会出错
    Py_XDECREF(args);
    Py_XDECREF(kwargs);
    return nullptr;
};

说明

  • 使用Py_XDECREF而非Py_DECREF,是因为kwargs可能为NULL,Py_XDECREF能安全处理这种情况。
  • 这一步在CPython中不会产生负面影响,因为CPython会额外处理参数引用,但PyPy依赖扩展作者手动管理这些参数的引用,所以必须显式释放。

内容的提问来源于stack exchange,提问作者Lalaland

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 16:15:43