2016-05-12 60 views
0

我在SWIG中有一個內存管理問題。如何釋放SWIG中定製構造函數中分配的內存?

我有此對象在C++(TestStruct.h):

struct Buffer { 
    uint8_t* data; 
    int length; 
} 

我希望能夠初始化使用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) 

循環中運行時,構造函數和析構函數被調用(我驗證與打印輸出),但它不會解決內存分配問題。

我需要緩衝區將它作爲參數傳遞給另一個SWIG包裝函數,我希望能夠使用python列表創建Buffer的數據。我嘗試使用或多或少具有相同代碼的typemaps(in和freearg),但失敗了。所以我想出了使用自定義構造函數和析構函數,但它不能解決內存泄漏的問題。任何輸入歡迎

回答

1

您在將Python列表轉換爲C++ uint8_t[leng]時使用Python C-API不正確,導致內存泄漏。重點是功能PySequence_GetItem()返回一個新參考到序列項目。由於您未能在該項目上調用Py_DECREF(),因此當列表本身被刪除時,Python不會釋放該項目的內存。

要解決,只需在for循環中添加Py_DECREF(o);即可。

順便說一下,Python循環中的線del buffer是多餘的。

+0

謝謝。它像一個魅力一樣工作! –

+0

還有一點需要注意。如果在C++中使用多線程,for循環的內部必須用'SWIG_PYTHON_THREAD_BEGIN_BLOCK;'和'SWIG_PYTHON_THREAD_END_BLOCK;'封裝,否則程序會在某個點崩潰 –