3

私は、私が書いた C++ クラスをラップする cython で書かれた python 拡張モジュールに取り組んでいます。

クラッシュ

このpythonモジュールをインポートしてデータを処理する単純なpythonコードがあります。現在、約 4 回に 1 回、モジュールの呼び出し後、終了直前にプログラムが segfault を起こします。これは、すべてのデータが正しく処理されていることも意味します。次のようにセグメンテーション違反します。

/Users/axe/anaconda/bin/python.app: line 2: 73168 Segmentation fault: 11

gdbでデバッグし、実行gdb pythonしてからrun code.py、取得します

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: 13 at address: 0x0000000000000000
0x00000001000894ae in PyObject_ClearWeakRefs ()

の出力backtrace

#0  0x00000001000894ae in PyObject_ClearWeakRefs ()
#1  0x00000001010edae4 in array_dealloc ()
#2  0x000000010007503e in tupledealloc ()
#3  0x00000001000559b7 in insertdict_by_entry ()
#4  0x0000000100059177 in PyDict_SetItem ()
#5  0x000000010005d286 in _PyModule_Clear ()
#6  0x00000001000df8cd in PyImport_Cleanup ()
#7  0x00000001000f0027 in Py_Finalize ()
#8  0x0000000100107e1b in Py_Main ()
#9  0x0000000100000f54 in start ()

したがって、segfault は私の python コードの外で発生します。ipython 内からコードを実行するか、interpter/ipython を Enthought ディストリビューションのものに変更するか、Cython を 1.9.1 から 1.6 にダウングレードすると、問題が解決しないことを述べます。

C++ でのメモリ リーク (?)

これは C++ コードのメモリ リークのように見える可能性があるため (他に考えられる説明があれば教えてください)、C++ クラスの C++ テスト コードで Valgrind を実行しましたが、問題は見つかりませんでした。(私は OSX Mountain Lion を使用しており、Valgrind の最新のトランク バージョンを使用しているにもかかわらず、問題があることが知られているため、問題がないことを 100% 確信しているわけではありません。OSX10.8 抑制ファイルを使用しています。ここで最初に提案されたもの)。とにかく、C++ クラスは new/delete/malloc/free を使用しないので、問題ないはずです。

Cython でのメモリ リーク (?)

クラッシュするpythonコードでvalgrindを実行してみました。上記の OSX 抑制ファイルに加えて、python 抑制ファイルを追加しました。Valgrind は大量の出力を生成してからクラッシュします。出力には、ソース コードへの参照はありません。これは、問題のある cython コードです。

def split_props(np.ndarray[fptype, ndim=1, mode="c"] x,
                   np.ndarray[fptype, ndim=1, mode="c"] y,
                   np.ndarray[fptype, ndim=1, mode="c"] ylines):

cdef np.ndarray[fptype, ndim = 1, mode = "c"] areas = np.zeros((ylines.shape[0] + 1), dtype=np.float64, order="c")
cdef np.ndarray[fptype, ndim = 1, mode = "c"] static_moments_x = np.zeros((ylines.shape[0] + 1), dtype=np.float64, order="c")
cdef np.ndarray[fptype, ndim = 1, mode = "c"] inertia_moments_xx = np.zeros((ylines.shape[0] + 1), dtype=np.float64, order="c")

cdef SplitPolygon * SPINSTANCE = new SplitPolygon(100, 100)

SPINSTANCE.split_props(& x[0],  # = <fptype *> x.data
                         & y[0],
                         x.shape[0],
                         & ylines[0],
                         ylines.shape[0],
                         & areas[0],
                         & static_moments_x[0],
                         & inertia_moments_xx[0]
                         )
del SPINSTANCE
return areas, static_moments_x, inertia_moments_xx

上記の C++ クラスは SplitPolygon です。Python コードでは、cython モジュールからsplit_props上記の関数のみをインポートするため、メモリ リークはコードのこの部分または C++ コードにあるに違いありません。さらに、Python コードの機能は C++ テスト コードと同じです。

モジュールの別の部分も以下に報告します。これは非常に似ていますが、メモリリークは発生しません

def SplitCirc(np.ndarray[fptype, ndim=1, mode="c"] ycenters,
               np.ndarray[fptype, ndim=1, mode="c"] radii,
               np.ndarray[fptype, ndim=1, mode="c"] ylines):

cdef np.ndarray[fptype, ndim = 1, mode = "c"] areas = np.zeros((len(ylines) + 1), dtype=np.float64, order="c")
cdef np.ndarray[fptype, ndim = 1, mode = "c"] static_moments_x = np.zeros((len(ylines) + 1), dtype=np.float64, order="c")
cdef np.ndarray[fptype, ndim = 1, mode = "c"] inertia_moments_xx = np.zeros((len(ylines) + 1), dtype=np.float64, order="c")

split_circles(& ycenters[0], & radii[0], len(ycenters),
              & ylines[0], len(ylines),
              & areas[0], & static_moments_x[0], & inertia_moments_xx[0])
return areas, static_moments_x, inertia_moments_xx

今、私はこの時点で本当に立ち往生しています。cython コードは適切に見えますか? C++ クラスの SplitPolygon に本当にリークがないことを確認するためにコーディングできるテスト ケースはありますか? 他の理由でクラッシュが発生する可能性はありますか?

4

1 に答える 1

1

コメントありがとうございます。あなたが指摘したように、それはメモリリークではありませんでした。

問題は、配列x,y,ylinesで渡されたデータにありました。これは、クラスの仕様を尊重していなかったため、間違っていましたSplitPol()

これによりSplitPols.split_props()、未定義の動作が発生しました。この場合、 への呼び出しでアドレスによって渡された 3 つの配列の境界の外側に書き込みが行われましたSPINSTANCE.split_props()

3 つの配列は、への 3 つの呼び出しで numpy によって割り当てられましたzeros()。破損したメモリはその近くにあり、実行ごとに重要な Python オブジェクトに属している可能性があり、セグメンテーション違反を引き起こしたり、そうでなかったりして、すべてが問題ないように見えました。

コードが正しいデータを返すことは助けにはなりませんでしたSplitPols.split_props()が、メモリをねじ込むことは別として。

于 2013-08-25T14:42:54.950 に答える