파이썬 C++ 확장을 작성했지만 기능 중 하나에 문제가 있습니다. 이 확장에서 제공하는 함수는 2 개의 배열을 입력으로 사용하고 하나는 출력으로 생성합니다. 파이썬 C++ 확장 - 메모리 누수 또는 액세스 위반
나는 단지 함수의 코드float* forward(float* input, float* kernels, npy_intp* input_dims, npy_intp* kernels_dims){
float* output = new float[output_size];
//some irrelevant matrix operation code
return output;
}
의 관련 부분 그리고 래퍼를 왼쪽했습니다
static PyObject *module_forward(PyObject *self, PyObject *args)
{
PyObject *input_obj, *kernels_obj;
if (!PyArg_ParseTuple(args, "OO", &input_obj, &kernels_obj))
return NULL;
PyObject *input_array = PyArray_FROM_OTF(input_obj, NPY_FLOAT, NPY_IN_ARRAY);
PyObject *kernels_array = PyArray_FROM_OTF(kernels_obj, NPY_FLOAT, NPY_IN_ARRAY);
if (input_array == NULL || kernels_array == NULL) {
Py_XDECREF(input_array);
Py_XDECREF(kernels_array);
return NULL;
}
float *input = (float*)PyArray_DATA(input_array);
float *kernels = (float*)PyArray_DATA(kernels_array);
npy_intp *input_dims = PyArray_DIMS(input_array);
npy_intp *kernels_dims = PyArray_DIMS(kernels_array);
/////////THE ACTUAL FUNCTION
float* output = forward(input, kernels, input_dims, kernels_dims);
Py_DECREF(input_array);
Py_DECREF(kernels_array);
npy_intp output_dims[4] = {input_dims[0], input_dims[1]-kernels_dims[0]+1, input_dims[2]-kernels_dims[1]+1, kernels_dims[3]};
PyObject* ret_output = PyArray_SimpleNewFromData(4, output_dims, NPY_FLOAT, output);
delete output;//<-----THE PROBLEMATIC LINE////////////////////////////
PyObject *ret = Py_BuildValue("O", ret_output);
Py_DECREF(ret_output);
return ret;
}
마법 일이 어디 강조 delete 연산자는 다음과 같습니다없이이 기능 누출 메모리, 메모리 액세스 위반으로 인해 충돌합니다.
재미있는 점은 두 개의 배열을 반환하는 또 다른 메서드를 작성한 것입니다. 그래서 함수는 두 개의 플로트 * 요소를 가리키는 ** float를 반환
float** gradients = backward(input, kernels, grads, input_dims, kernel_dims, PyArray_DIMS(grads_array));
Py_DECREF(input_array);
Py_DECREF(kernels_array);
Py_DECREF(grads_array);
PyObject* ret_g_input = PyArray_SimpleNewFromData(4, input_dims, NPY_FLOAT, gradients[0]);
PyObject* ret_g_kernels = PyArray_SimpleNewFromData(4, kernel_dims, NPY_FLOAT, gradients[1]);
delete gradients[0];
delete gradients[1];
delete gradients;
PyObject* ret_list = PyList_New(0);
PyList_Append(ret_list, ret_g_input);
PyList_Append(ret_list, ret_g_kernels);
PyObject *ret = Py_BuildValue("O", ret_list);
Py_DECREF(ret_g_input);
Py_DECREF(ret_g_kernels);
return ret;
주의 두 번째 예는 완벽하게, 아니 충돌하거나 메모리 누수, 작동 그들이 PyArray 객체에 내장 된 후에도 배열에 delete
를 호출하는 동안 .
여기에 무슨 일이 일어나고 있는지 나에게 누군가 가르쳐 주시겠습니까? PyArray_SimpleNewFromData
docs에서
나는 그런 식으로 작동한다고 생각했지만 두 번째 예제는 동의하지 않습니다. 나는 포인터도 거기에서 삭제한다. 그리고 웬일인지 모든 것이 작동한다. – Lugi
@Lugi : 정의되지 않은 동작은 충돌 할 필요가 없습니다. C++은 좋은 언어가 아닙니다. 코드가 충돌하지 않고 실행되는 것처럼 보이기 때문에 코드가 정확하다고 생각하지 마십시오. – user2357112
예를 들어'PyArray_Zeros' 메소드를 사용하여 생성 된 배열을 C 배열의 원하는 값으로 채우고'PyArray_SimpleNewFromData'로 만든 배열은 똑같이 동작하지 않을까요? – Lugi