简单的 Python C 扩展中的内存泄漏

问题描述 投票:0回答:1

我有一些类似于下面的代码。那个代码泄露了,我不知道为什么。泄漏的是在 C 代码中简单创建 Python 类的实例。我用来检查泄漏的函数是

create_n_times
,它在下面定义并且只是创建新的 Python 实例并在循环中取消引用它们。

这本身不是 MWE,而是示例的一部分。为了更容易理解,代码所做的是:

  1. Python 代码定义数据类并使用
    set_ip_settings_type
    将其注册到 C 扩展中。
  2. 然后,一个 C 扩展函数
    create_n_times
    被调用,该函数创建和销毁 Python 数据类的
    n
    实例。

有人能帮忙吗?

在 Python 中:

import c_api

@dataclass
class IpSettings:
    ip: str
    port: int
    dhcp: bool

c_api.set_ip_settings_type(IpSettings)
c_api.generate_n_times(100000)

在 C++ 中,我将以下代码编译成一个名为

c_api
的 Python 扩展(它是该库定义的一部分):

#include <Python.h>

// ... Other functions including a "PyInit" function

extern "C" {
    
PyObject* ip_settings_type = NULL;
PyObject* set_ip_settings_type(PyObject* tp)
{
    Py_XDECREF(ip_settings_type);
    Py_INCREF(tp);
    ip_settings_type = tp;
    return Py_None;
}

PyObject* create_n_times(PyObject* n)
{
   long n_ = PyLong_AsLong(n);
   for (int i = 0; i < n_ ++i)
   {
       PyObject* factory_object = ip_settings_type;

       PyObject* args = PyTuple_New(3);
       PyTuple_SetItem(args, 0, PyUnicode_FromString("123.123.123.123"));
       PyTuple_SetItem(args, 1, PyLong_FromUnsignedLong(1231));
       PyTuple_SetItem(args, 2, Py_False);

       PyObject* obj = PyObject_CallObject(factory_object, args);
       Py_DECREF(obj);
   }

    return Py_None;
}

}
python c python-c-api
1个回答
2
投票

PyTuple_SetItem
窃取了对所提供对象的引用,但是
Py_False
是单个对象。当 args 元组被销毁时,Py_False 的引用计数会被破坏。

使用

PyBool_FromLong(0)
创建对
Py_False
的新引用,就像对
PyTuple_SetItem
的其他两个调用一样。 (参见 docs.python.org/3/c-api/bool.html)

© www.soinside.com 2019 - 2024. All rights reserved.