我有一个关于 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()
返回序列项的新引用。因为您未能对该项目调用 Py_DECREF()
,所以当列表本身被删除时,Python 不会释放该项目的内存。
要修复,您只需在 for 循环中添加 Py_DECREF(o);
。
顺便说一下,Python 循环中的 del buffer
行是多余的。
关于python - 如何释放在 SWIG 的自定义构造函数中分配的内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37186737/