exponenta event banner

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

Обзор

Примечание

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

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

Как правило, MathWorks ® рекомендует, чтобы функции MEX уничтожали их собственные временные массивы и освобождали их динамически выделяемую память. Более эффективно выполнить эту очистку в исходном MEX-файле, чем полагаться на автоматический механизм. Этот подход согласуется с другими приложениями MATLAB API (приложениями MAT-файлов, приложениями ядра и приложениями 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, а затем с помощью mxSetDoubles, MATLAB все еще освободил исходную память. 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, и деструктор освобождают одну и ту же память, что может повредить память.

См. также

|

Связанные темы