Проблемы управления памятью Python CFFI
Я программирую на Ubuntu, с Python 2.7.3
,
Я использую CFFI для заполнения списка Python значениями, взятыми из некоторого C-кода.
Этот список довольно большой: около 71 000 символов при печати.
Код C использует много библиотек. Следовательно, следующий код предназначен только для лучшего понимания происходящего.
datas_list = []
for i in range( 0, x ):
c_pDataStructure = ffi.new( "c_DataStructure[]", 1 ) // Create a pointer to the data structure
c.SomeCFunction( c_pDataStructure ) // Populate the data structure
datas_list.append( c.GetSomeInfo( c_pDataStructure ) ) // Get some info from the data structure
c.FreeDataStructure( c_pDataStructure ) // Release dynamically allocated memory
Программа хорошо работает с использованием Wingware IDE, но заканчивается ошибкой glibc (*** glibc detected *** python: free(): invalid next size (fast): 0x0000000003b0b080 ***
) при запуске из командной строки, прямо перед:
c_pDataStructure = ffi.new( "c_Datastructure[]", 1)
Прочитав ответ wim, я проверил, выполняли ли код в IDE и командной строке один и тот же интерпретатор - они есть (/usr/bin/python
).
РЕДАКТИРОВАТЬ (отчет Valgrind):
==5089== Process terminating with default action of signal 11 (SIGSEGV)
==5089== General Protection Fault
==5089== at 0x54FBB0: PyObject_Malloc (in /usr/bin/python2.7)
==5089== by 0x10B30625: allocate_owning_object (_cffi_backend.c:2972)
==5089== by 0x10B40EE8: allocate_with_allocator.constprop.84 (_cffi_backend.c:3032)
==5089== by 0x10B41010: direct_newp (_cffi_backend.c:3153)
==5089== by 0x10B4138C: b_newp (_cffi_backend.c:3177)
==5089== by 0x4F95A4: PyEval_EvalFrameEx (in /usr/bin/python2.7)
==5089== by 0x5008C1: PyEval_EvalCodeEx (in /usr/bin/python2.7)
==5089== by 0x4F9AB7: PyEval_EvalFrameEx (in /usr/bin/python2.7)
==5089== by 0x4F9D01: PyEval_EvalFrameEx (in /usr/bin/python2.7)
==5089== by 0x4F9D01: PyEval_EvalFrameEx (in /usr/bin/python2.7)
==5089== by 0x4F9D01: PyEval_EvalFrameEx (in /usr/bin/python2.7)
==5089== by 0x4F9D01: PyEval_EvalFrameEx (in /usr/bin/python2.7)
РЕДАКТИРОВАТЬ:
Вот еще немного информации о структуре данных C. Вот как это выглядит:
typedef struct _STRUCT3{
some int, char*
}STRUCT3, *PSTRUCT3;
typedef struct _STRUCT2{
some int
PSTRUCT3 pStruct3;
}STRUCT3, *PSTRUCT3;
typedef struct _STRUCT1{
some int, char*
PSTRUCT2 pStruct2;
}STRUCT1, *PSTRUCT1;
Я сделал небольшую C-программу для выделения / освобождения полной C-структуры и valgrind
не обнаружил утечки памяти.
Вопросы:
- Что говорит выше
valgrind
отчет точно значит? - В чем могут быть различия между запуском программы из IDE и из командной строки?
Примечание. В среде IDE используется аргумент Python.-u (unbuffered)
запустить программу, но добавление ее в командную строку не имеет значения. - Когда я освобождаю структуру самостоятельно, работает ли сборщик мусора в Python? Должен ли я использовать
ffi.gc( c_pDataStructure, c.FreeDataStructure )
вместо?
2 ответа
Я нашел, как исправить мои проблемы:
я использовал ffi.gc(cdata, destructor)
создать структуру. Мой код Python теперь выглядит так:
data_list = []
for i in range( 0, x ):
# Create a pointer to the data structure and tell the garbage collector how to destroy it
gc_c_pDataStructure = ffi.gc( c.CreateDataStructure(), c.FreeDataStructure )
c.SomeCFunction( gc_c_pDataStructure ) # Populate the data structure
datas_list.append( c.GetSomeInfo( gc_c_pDataStructure ) ) # Store some data
Вот некоторые ссылки, связанные с ffi.gc()
:
А вот функция C для создания структуры данных (в соответствии с примером структуры из вопроса):
PSTRUCT1 CreateDataStructure()
{
PSTRUCT1 pStruct1 = ( PSTRUCT1 ) malloc( sizeof( STRUCT1 ) );
_SetDummyValues( pStruct1 );
return pStruct1;
}
Как видите, мне пришлось создать функцию void _SetDummyValues( PSTRUCT1 pStruct1 )
, Эта функция устанавливает указанные указатели структуры в NULL.
Это также может быть связано с этой ошибкой, которую Coverity обнаружил в некоторых наших сгенерированных CFFI-кодах:
x0 = (void *)alloca((size_t)datasize);
...
{
free(x0);
}
Как вы можете видеть, он вызывается бесплатно в памяти, выделенной стеком.