Мне удалось реализовать функцию перемешивания Фишера-Йейтса для списков Python в качестве упражнения для привыкания к расширению Python. Он отлично работает для относительно небольших списков, если только я не запускаю функцию несколько раз.
Всякий раз, когда размер списка превышает 100, я получаю всевозможные проблемы с памятью:
>>>import evosutil
>>> a=[i for i in range(100)]
>>> evosutil.shuffle(a)
>>> a
[52, 66, 0, 58, 41, 18, 50, 37, 81, 43, 74, 49, 90, 20, 63, 32, 89, 60, 2, 44, 3, 80, 15, 24, 22, 69, 86, 31, 56, 68, 34, 13, 38, 26, 14, 91, 73, 79, 39, 65, 5, 75, 84, 55, 7, 53, 93, 42, 40, 9, 51, 82, 29, 30, 99, 64, 33, 97, 27, 11, 6, 67, 16, 94, 95, 62, 57, 17, 78, 77, 71, 98, 72, 8, 88, 36, 85, 59, 21, 96, 23, 46, 10, 12, 48, 83, 4, 92, 45, 54, 1, 25, 19, 70, 35, 61, 47, 28, 87, 76]
>>> (Ctrl-D)
*** Error in `python3': free(): invalid next size (fast): 0x083fe680 ***
Или при попытке работать со списком из 1000 элементов:
*** Error in `python3': munmap_chunk(): invalid pointer: 0x083ff0e0 ***
Or,
Segmentation fault (core dumped)
Вот мой код модуля, выдающего ошибку:
inline void _List_SwapItems(PyObject* list, Py_ssize_t i1, Py_ssize_t i2){
PyObject* tmp=PyList_GetItem(list, i2);
PyList_SetItem(list, i2, PyList_GetItem(list, i1));
PyList_SetItem(list, i1, tmp);
}
//Naive Fisher–Yates shuffle
static PyObject* shuffle(PyObject* self, PyObject* args){
PyObject* list;
PyArg_ParseTuple(args,"O", &list);
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
std::minstd_rand0 rand(seed);
Py_ssize_t size = PyList_Size(list);
for(int i=0; i<size;++i){
int randIndex = rand()%size;
_List_SwapItems(list, randIndex, i);
}
Py_RETURN_NONE;
}
Я чувствую, что должен решить это либо с помощью free(), либо с помощью Py_DECREF() где-то, но я не вижу, где. Я не думаю, что создаю какие-либо объекты, просто перемещаю их. Так откуда берется проблема с памятью?