2016-03-29 18 views
0

私はUbuntuでプログラミングしています(Python 2.7.3)。Python CFFIメモリ管理の問題

私はCFFIを使用して、PythonリストにいくつかのCコードからの値を移入しています。
このリストはかなり大きく、印刷すると約71000文字です。

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 ***)で終了します。WIMのanswerを読んだ後

c_pDataStructure = ffi.new("c_Datastructure[]", 1) 

両方の場合、私がチェックIDEとコマンドラインは同じインタプリタを使用してコードを実行していました - (/usr/bin/python)です。

EDIT(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) 

EDIT:
ここでは、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)を使用する必要がありますか?
+0

'FreeDataStructure(p)'はポインタ '' p''自体を解放するべきではなく、内部に動的に割り当てられたものだけを解放すべきです。私はこれが当てはまると思いますか? –

+0

はい、FreeDataStructureは、ポピュレート関数が動的に割り当てたすべてを解放します – DRz

+0

オプションのメンバーを持つデータ構造が33回目に割り当てられた後、プログラムがクラッシュします。したがって、私はオプションの値が適切に解放されないことを疑う。以前に使用されたメモリアドレスを上書きする前に、Python(またはCFFIまたはC?)が "32メモリアドレス範囲"に入っていませんか?次に、Wingwareが64ビットPythonでコマンドラインを実行し、32ビットPythonでコマンドラインを実行すると、後者がglibcエラーで終了する理由を説明することができます... – DRz

答えて

0

私は私の問題を修正する方法が見つかりました:

私は構造を作成する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に設定します。あなたが見ることができるように、それはスタックに割り当てられたメモリの空きを呼んだ

x0 = (void *)alloca((size_t)datasize); 
    ... 
    { 
     free(x0); 
    } 

+1

違いがあります:元のコードでは、 'c.FreeDataStructure(p)'は 'p = ffi.new()'の後に自動的に行われるため 'free(p)'を呼び出すべきではありません。ここで修正されたコードでは、 'c.FreeDataStructure(p)'は 'malloc()'を呼び出す 'c.CreateDataStructure()'に対応して 'free(p)'を呼び出さなければなりません。そうでなければ、漏れがあります。 –

+1

一方、 'free(p)'を呼び出していつもした場合、クラッシュの元の理由がわかりました---二重解放! –

+0

'ffi.gc()'を使う前に 'free(p)'を削除しなければならなかったのは覚えています。そして、あなたが正しいです、私のプログラムは、私は再びその行を追加することを忘れていたので、漏れていました。ありがとう! – DRz

0

また、これは、コベリティが 当社CFFI生成されたコードの一部で見つかったこのバグに関連している可能性があります。