7

関数を呼び出すたびに、呼び出しごとにメモリ使用量が約 +10M 増加するため、ここでメモリ リークが発生していると思われます。

....
PyObject *pair = PyTuple_New(2), *item = PyList_New(0);

PyTuple_SetItem(pair, 0, PyInt_FromLong(v[j]));

if(v[j] != DISTANCE_MAX && (p[j] || d[0][j])){
  jp=j;
  while(jp!=istart) {
    PyList_Append(item, PyInt_FromLong(jp));
    jp=p[jp];
  }

  PyList_Append(item, PyInt_FromLong(jp));

  PyList_Reverse(item);
}

PyTuple_SetItem(pair, 1, item);

return pair;
....

ドキュメントを読むと、次のような呼び出しがいくつかあります

void
bug(PyObject *list)
{
    PyObject *item = PyList_GetItem(list, 0);

    PyList_SetItem(list, 1, PyInt_FromLong(0L));
    PyObject_Print(item, stdout, 0); /* BUG! */
}

このような参照カウントを配置する必要があります

void
no_bug(PyObject *list)
{
    PyObject *item = PyList_GetItem(list, 0);

    Py_INCREF(item);
    PyList_SetItem(list, 1, PyInt_FromLong(0L));
    PyObject_Print(item, stdout, 0);
    Py_DECREF(item);
}

では、関数のどこに Py_INCREF と Py_DECREF を配置すればよいでしょうか?

4

2 に答える 2

11

PyInt_FromLong() で作成してリストに追加するオブジェクトは、ローカル変数に保持する必要があります。

その理由は所有権の規則です: PyInt_FromLong() はあなたが所有する参照を生成します。PyTuple_SetItem() の呼び出しでは、PyTuple_SetItem() が所有権を「盗む」ため、この所有権を再び失います。そのため、気にする必要はありません。しかし、PyList_Append() はそうしません。refcount を増やします。オブジェクトを正しく GC するためには、DECREF によって所有権を解放する必要があります。

したがって、PyList_Append(item, PyInt_FromLong(jp)) の代わりに、次のようにします。

PyObject * jpo = PyInt_FromLong(jp);
// do some error checking here
PyList_Append(item, jpo);
Py_DECREF(jpo);

これにより、プログラムは正しいことを行います。

于 2011-08-08T07:25:37.323 に答える
0

オブジェクトが作成されると、その参照カウントは 1 になるため、この後は次のようになります。

my_item  = PyInt_FromLong(jp)

オブジェクトmy_itemの refcount は 1 です。

アイテムをコンテナーに格納すると、アイテムの参照カウントがインクリメントされるため、アイテムが保持されるため、この後は次のようになります。

PyList_Append(my_list, my_item);

オブジェクトmy_itemの refcount は 2 です。

したがって、この行:

PyList_Append(item, PyInt_FromLong(jp));

refcount 1 でオブジェクトを作成し、それをリストに格納して、オブジェクトの refcount を 2 にインクリメントします。

于 2011-08-08T02:27:26.730 に答える