Когда MEX-функция возвращает управление в MATLAB®, это возвращает результаты своих вычислений в выходных аргументах — mxArray
s содержавшийся в аргументах 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, чтобы избегать использования этих функций в следующих ситуациях. Для получения дополнительной информации смотрите Автоматическую Очистку Временных массивов и Персистентного 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.
Если вы вызываете mxSetPr
, mxSetPi
, mxSetData
или mxSetImagData
, задавая память, которая не была выделена 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); mxSetPr(temp, data); /* INCORRECT */
Вместо того, чтобы использовать mxSetPr
, чтобы установить указатель данных, вместо этого, создать mxArray
с правильным размером и использовать memcpy
, чтобы скопировать данные стека в буфер, возвращенный mxGetPr
:
mxArray *temp = mxCreateDoubleMatrix(1,5,mxREAL); double data[5] = {1,2,3,4,5}; ... memcpy(mxGetPr(temp), data, 5*sizeof(double)); /* CORRECT */
Перед Версией 5.2, если вы создали mxArray
с помощью одной из стандартных программ создания API и затем вы перезаписали указатель на данные с помощью mxSetPr
, MATLAB все еще освободил исходную память. MATLAB больше не освобождает память.
Например:
pr = mxCalloc(5*5, sizeof(double)); ... <load data into pr> plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL); mxSetPr(plhs[0], pr); /* INCORRECT */
теперь 5*5*8 байтов утечек памяти, где 8 байтов размер double
.
Можно избежать что утечка памяти путем изменения кода на:
plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL); pr = mxGetPr(plhs[0]); ... <load data into pr>
или альтернативно:
pr = mxCalloc(5*5, sizeof(double)); ... <load data into pr> plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL); mxFree(mxGetPr(plhs[0])); mxSetPr(plhs[0], pr);
Первое решение более эффективно.
Подобные утечки памяти могут также произойти при использовании mxSetPi
, mxSetData
, mxSetImagData
, 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);
Не используйте mxFree
или функции mxDestroyArray
в деструкторе C++ класса, используемого в MEX-функции. Если MEX-функция выдает ошибку, MATLAB очищает переменные файла MEX, как описано в Автоматической Очистке Временных массивов.
Если ошибка происходит, который заставляет объект, выходят из осциллографа, MATLAB вызывает деструктор C++. Освобождение памяти непосредственно в деструкторе означает, что и MATLAB и деструктор освобождают ту же память, которая может повредить память.