Проблемы управления памятью

Обзор

Примечание

Примеры в этой теме используют функции в чередующемся комплексном API. Чтобы создать приложения с этими функциями, вызовите mex с помощью специфичного для release опции -R2018a.

Когда MEX-функция возвращает управление в MATLAB®, он возвращает результаты своих расчетов в выходных аргументах - mxArrays, содержащиеся в аргументах с левой стороны plhs[]. Эти массивы должны иметь временные возможности, поэтому не передавать массивы, созданные с mexMakeArrayPersistent функция в plhs. MATLAB уничтожает любые mxArray созданный MEX-функцией, которая не находится в plhs. MATLAB также освобождает любую память, которая была выделена в MEX-функция, используя mxCalloc, mxMalloc, или mxRealloc функций.

В целом, MathWorks® рекомендует, чтобы MEX-функции уничтожали свои собственные временные массивы и освобождали свою динамически выделенную память. Более эффективно выполнить эту очистку в исходном файле MEX, чем полагаться на автоматический механизм. Этот подход согласуется с другими приложениями MATLAB API (приложениями MAT-файлов, приложениями engine и MATLAB Compiler™, созданными приложениями, которые не имеют никакого механизма автоматической очистки.)

Однако не уничтожайте mxArray в исходном файле MEX, когда он:

  • передан в файл MEX в списке справа prhs[]

  • возвращается в списке слева plhs[]

  • возвращено mexGetVariablePtr

  • используется для создания структуры

В этом разделе описываются ситуации, характерные для управления памятью. Мы рекомендуем вам просмотреть код в ваших исходных файлах MEX, чтобы избежать использования этих функций в следующих ситуациях. Для получения дополнительной информации смотрите Автоматическая очистка временных массивов в файлах MEX и постоянных mxArrays. Для руководства по вопросам памяти смотрите Стратегии эффективного использования памяти.

Потенциальные проблемы управления памятью включают:

Неправильное уничтожение mxArray

Не используйте mxFree чтобы уничтожить mxArray.

Пример

В следующем примере, mxFree не уничтожает объект массива. Эта операция освобождает заголовок структуры, сопоставленный с массивом, но MATLAB все еще работает так, как будто объект массива нужно уничтожить. Таким образом MATLAB пытается уничтожить объект массива, и в процессе снова пытается освободить его заголовок структуры:

mxArray *temp = mxCreateDoubleMatrix(1,1,mxREAL);
      ...
mxFree(temp);  /* INCORRECT */

Решение

Звонить mxDestroyArray вместо этого:

mxDestroyArray(temp);  /* CORRECT */

Неправильное построение камеры или структуры mxArray

Не звонить mxSetCell или mxSetField варианты с prhs[] как массив представителей.

Пример

В следующем примере, когда файл MEX возвращается, MATLAB уничтожает весь массив ячеек. Поскольку это включает в себя представителей камеры, это неявно уничтожает входные параметры файла MEX. Это может привести к нескольким странным результатам, обычно связанным с повреждением рабочей области вызывающего абонента, если используемый правый аргумент является временным массивом (для примера, литералом или результатом выражения):

myfunction('hello')
/* myfunction is the name of your MEX file and your code
/* contains the following:    */

    mxArray *temp = mxCreateCellMatrix(1,1);
      ...
    mxSetCell(temp, 0, prhs[0]);  /* INCORRECT */

Решение

Сделайте копию аргумента правой стороны с mxDuplicateArray и используйте эту копию в качестве аргумента для mxSetCell (или mxSetField варианты). Для примера:

mxSetCell(temp, 0, mxDuplicateArray(prhs[0]));  /* CORRECT */

Создание временной mxArray с неподходящими данными

Не звонить mxDestroyArray на mxArray данные которого не были выделены стандартной программой API.

Пример

Если вы звоните mxSetDoubles, mxSetComplexDoubles, или любая из типизированных функций доступа к данным, задающих память, которая не была выделена mxCalloc, mxMalloc, или mxRealloc как предполагаемый блок данных (второй аргумент), затем, когда файл MEX возвращается, MATLAB пытается освободить указатели на реальные данные и мнимые данные (если таковые имеются). Таким образом MATLAB пытается освободить память, в этом примере, из программного стека:

mxArray *temp = mxCreateDoubleMatrix(0,0,mxREAL);
double data[5] = {1,2,3,4,5};
      ...
mxSetM(temp,1); mxSetN(temp,5); mxSetDoubles(temp, data); 
/* INCORRECT */

Решение

Вместо использования mxSetDoubles чтобы задать указатель на данные, создайте mxArray с правильным размером и использованием memcpy чтобы скопировать данные стека в буфер, возвращенный mxGetDoubles:

mxArray *temp = mxCreateDoubleMatrix(1,5,mxREAL);
double data[5] = {1,2,3,4,5};
      ...
memcpy(mxGetDoubles(temp), data, 5*sizeof(double)); /* CORRECT */

Создание потенциальных утечек памяти

До версии 5.2, если вы создали mxArray используя одну из стандартных программ создания API, а затем вы перезаписываете указатель на данные, используя mxSetDoublesMATLAB все еще освободил исходную память. MATLAB больше не освобождает память.

Для примера:

pr = mxCalloc(5*5, sizeof(double));
... <load data into pr>
plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL);
mxSetDoubles(plhs[0], pr);  /* INCORRECT */

теперь течет 5 * 5 * 8 байтов памяти, где 8 байтов размером с double.

Можно избежать утечки памяти, изменив код на:

plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL);
pr = mxGetDoubles(plhs[0]);
... <load data into pr> 

или альтернативно:

pr = mxCalloc(5*5, sizeof(double));
... <load data into pr>
plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL);
mxFree(mxGetDoubles(plhs[0]));
mxSetDoubles(plhs[0], pr);

Первое решение является более эффективным.

Подобные утечки памяти также могут произойти при использовании mxSetDoubles, mxSetComplexDoubles, mxSetIr, mxSetJcили любую из функций доступа к данным с числовым типом. Можно избежать утечек памяти, изменив код, как описано в этом разделе.

Неправильное уничтожение структуры

Для структуры необходимо вызвать mxDestroyArray только в структуре, а не в массивах полевых данных. Поле в структуре указывает на данные в массиве, используемом mxSetField или mxSetFieldByNumber. Когда mxDestroyArray уничтожает структуру, она пытается пройти вниз через себя и освободить все другие данные, включая память в массивах данных. Если вы звоните mxDestroyArray на каждом массиве данных одна и та же память освобождается дважды, что может привести к повреждению памяти.

Пример

В следующем примере создаются три массива: один массив структур aStruct и два массива данных, myDataOne и myDataTwo. Имя поля one содержит указатель на данные в myDataOne, и имя поля two содержит указатель на данные в myDataTwo.

mxArray *myDataOne; 
mxArray *myDataTwo; 
mxArray *aStruct; 
const char *fields[] = { "one", "two" }; 
 
myDataOne = mxCreateDoubleScalar(1.0); 
myDataTwo = mxCreateDoubleScalar(2.0); 
 
aStruct = mxCreateStructMatrix(1,1,2,fields); 
mxSetField( aStruct, 0, "one", myDataOne ); 
mxSetField( aStruct, 1, "two", myDataTwo ); 
mxDestroyArray(myDataOne); 
mxDestroyArray(myDataTwo);
mxDestroyArray(aStruct); /* tries to free myDataOne and myDataTwo */

Решение

Область команды mxDestroyArray(aStruct) уничтожает данные во всех трех массивах:

      ...
aStruct = mxCreateStructMatrix(1,1,2,fields); 
mxSetField( aStruct, 0, "one", myDataOne ); 
mxSetField( aStruct, 1, "two", myDataTwo ); 
mxDestroyArray(aStruct); 

Уничтожение памяти в деструкторе классов C++

Не используйте mxFree или mxDestroyArray функции в деструкторе C++ класса, используемого в MEX-функции. Если MEX-функция выдает ошибку, MATLAB очищает Файл MEX переменные, как описано в Автоматической очистке временных массивов в Файлы MEX.

Если возникает ошибка, из-за которой объект выходит из возможностей, MATLAB вызывает деструктор C++. Освобождение памяти непосредственно в деструкторе означает, что и MATLAB, и деструктор освобождают одну и ту же память, что может испортить память.

См. также

|

Похожие темы