如何释放在 SWIG 的自定义构造函数中分配的内存?
How to release memory allocated in custom Constructor in SWIG?
我有 SWIG 中的内存管理问题。
我在 C++ 中有这个对象 (TestStruct.h):
struct Buffer {
uint8_t* data;
int length;
}
我希望能够使用 python 列表或字符串初始化此对象并从 python 中销毁它而不会发生内存泄漏。
我的痛饮文件是:
%module test
%newobject Buffer;
%nodefaultctor Buffer;
%nodefaultdtor Buffer;
%{
#include "TestStruct.h"
%}
%include "TestStruct.h"
%extend Buffer {
Buffer(PyObject* inputList)
{
int leng = (int)PySequence_Length(inputList);
uint8_t* temp = new uint8_t[leng];
cout << "Buffer Constructor called: " << leng << " " << (unsigned int)temp << endl;
for(int i=0; i<leng; i++){
PyObject *o = PySequence_GetItem(inputList,i);
if (PyNumber_Check(o)) {
temp[i] = (uint8_t) PyLong_AsLong(o);
//cout << "uint8_t to C++: " << (int)temp[i] << endl;
} else {
PyErr_SetString(PyExc_ValueError,"Sequence elements must be integers");
return NULL;
}
}
Buffer* buff = new Buffer();
buff->dataBuf = temp;
buff->length = leng;
return buff;
}
~Buffer() {
cout << "Buffer Destructor called: " << $self->length << " " << (unsigned int)$self->dataBuf << endl;
delete[] $self->dataBuf;
delete $self;
}
}
运行 下面的简单测试使 Python 的内存使用量飙升至 30MB
import test
import sys
import time
times = 1000
printsteps = False
print("performing memory stress test")
for j in range(times):
sizeBytes = 1024 * 1
input_list = list(range(sizeBytes))
buffer = test.Buffer(input_list)
del buffer
time.sleep(0.001)
每次循环运行,构造函数和析构函数都被调用(我用打印输出验证),但它不会解决内存分配问题。
我需要 Buffer 将其作为参数传递给另一个 SWIG 包装的函数,并且我希望能够使用 python 列表创建 Buffer 的数据。我尝试使用大致相同的代码使用类型映射(in 和 freearg),但它失败了。所以我想出了使用自定义构造函数和析构函数,但它不会解决内存泄漏的问题。欢迎任何输入
您在将 Python 列表转换为 C++ uint8_t[leng]
时对 Python C-API 的使用不正确并导致内存泄漏。重点是函数 PySequence_GetItem()
returns 对序列项的 新引用 。因为您未能对该项目调用 Py_DECREF()
,所以当列表本身被删除时,Python 将不会释放该项目的内存。
要修复,您只需在 for 循环中添加 Py_DECREF(o);
。
顺便说一下,Python 循环中的 del buffer
行是多余的。
我有 SWIG 中的内存管理问题。
我在 C++ 中有这个对象 (TestStruct.h):
struct Buffer {
uint8_t* data;
int length;
}
我希望能够使用 python 列表或字符串初始化此对象并从 python 中销毁它而不会发生内存泄漏。 我的痛饮文件是:
%module test
%newobject Buffer;
%nodefaultctor Buffer;
%nodefaultdtor Buffer;
%{
#include "TestStruct.h"
%}
%include "TestStruct.h"
%extend Buffer {
Buffer(PyObject* inputList)
{
int leng = (int)PySequence_Length(inputList);
uint8_t* temp = new uint8_t[leng];
cout << "Buffer Constructor called: " << leng << " " << (unsigned int)temp << endl;
for(int i=0; i<leng; i++){
PyObject *o = PySequence_GetItem(inputList,i);
if (PyNumber_Check(o)) {
temp[i] = (uint8_t) PyLong_AsLong(o);
//cout << "uint8_t to C++: " << (int)temp[i] << endl;
} else {
PyErr_SetString(PyExc_ValueError,"Sequence elements must be integers");
return NULL;
}
}
Buffer* buff = new Buffer();
buff->dataBuf = temp;
buff->length = leng;
return buff;
}
~Buffer() {
cout << "Buffer Destructor called: " << $self->length << " " << (unsigned int)$self->dataBuf << endl;
delete[] $self->dataBuf;
delete $self;
}
}
运行 下面的简单测试使 Python 的内存使用量飙升至 30MB
import test
import sys
import time
times = 1000
printsteps = False
print("performing memory stress test")
for j in range(times):
sizeBytes = 1024 * 1
input_list = list(range(sizeBytes))
buffer = test.Buffer(input_list)
del buffer
time.sleep(0.001)
每次循环运行,构造函数和析构函数都被调用(我用打印输出验证),但它不会解决内存分配问题。
我需要 Buffer 将其作为参数传递给另一个 SWIG 包装的函数,并且我希望能够使用 python 列表创建 Buffer 的数据。我尝试使用大致相同的代码使用类型映射(in 和 freearg),但它失败了。所以我想出了使用自定义构造函数和析构函数,但它不会解决内存泄漏的问题。欢迎任何输入
您在将 Python 列表转换为 C++ uint8_t[leng]
时对 Python C-API 的使用不正确并导致内存泄漏。重点是函数 PySequence_GetItem()
returns 对序列项的 新引用 。因为您未能对该项目调用 Py_DECREF()
,所以当列表本身被删除时,Python 将不会释放该项目的内存。
要修复,您只需在 for 循环中添加 Py_DECREF(o);
。
顺便说一下,Python 循环中的 del buffer
行是多余的。