2016-08-06 22 views
1

私はCライブラリとデータを交換するためにctypesを使用しています。呼び出しインタフェースにはネストされたポインタから構造体が含まれています。ctypesはいつメモリを解放しますか?

メモリがCから割り当てられた場合、pythonは必要な値のコピーを(深く)抽出し、そのCライブラリにメモリの割り当てを明示的に要求する必要があります。

メモリがPythonから割り当てられた場合、対応するctypesオブジェクトがスコープから外れた直後にメモリが割り当て解除される可能性があります。これはポインタのためにどのように機能しますか?私は文字列バッファからポインタオブジェクトを作成する場合、このポインタがぶら下がるのを防ぐために、元のバッファオブジェクトをスコープ内で参照する変数を保持する必要がありますか?または、ポインタオブジェクト自体が私のために自動的にこれを行います(元のオブジェクトを返さなくても)? pointerPOINTERcastc_void_pfrom_address(addressof)のいずれを使用していても違いはありますか?

+0

私は、プログラムが終了したときに限りそうだと思います。 – YOU

答えて

0

単純なオブジェクトへのネストされたポインタはうまくいくようです。ドキュメンテーションはctypesが "元のオブジェクトの復帰"をサポートしていないことを明示していますが、ポインターがPythonリファレンスを保持してターゲットオブジェクトをキープアライブすることを意味しています。

>>> from ctypes import * 
>>> x = c_int(7) 
>>> triple_ptr = pointer(pointer(pointer(x))) 
>>> triple_ptr.contents.contents.contents.value == x.value 
True 
>>> triple_ptr.contents.contents.contents is x 
False 
>>> triple_ptr._objects['1']._objects['1']._objects['1'] is x # CPython 3.5 
True 

ポインタ機能(create_string_bufferc_char * sizeに関するどのような)POINTERテンプレートコンストラクタに異なっていないように見えます。

>>> type(pointer(x)) is type(POINTER(c_int)(x)) 
True 

voidへのキャストも参照を保持しているようです(ただし、元のポインタを変更する理由はわかりません)。

>>> ptr = pointer(x) 
>>> ptr._objects 
{'1': c_int(7)} 
>>> pvoid = cast(p, c_void_p) 
>>> pvoid._objects is ptr._objects 
True 
>>> pvoid._objects 
{139665053613048: <__main__.LP_c_int object at 0x7f064de87bf8>, '1': c_int(7)} 
>>> pvoid._objects['1'] is x 
True 

オブジェクトをメモリバッファ(またはそのアドレス)から直接作成することは、いっそう厄介です。

>>> v = c_void_p.from_buffer(triple_ptr) 
>>> v2 = c_void_p.from_buffer_copy(triple_ptr) 
>>> type(v._objects) 
<class 'memoryview'> 
>>> POINTER(POINTER(POINTER(c_int))).from_buffer(v)[0][0][0] == x.value 
True 
>>> p3 = POINTER(POINTER(POINTER(C_int))).from_address(addressof(triple_ptr)) 
>>> v2._objects is None is p3._objects is p3._b_base_ 
True 

ちなみに、byrefはおそらくそれが参照するメモリを保持しています。

>>> byref(x)._obj is x 
True 
関連する問題