内存管理问题
概述
请注意
本主题中的示例使用交错复杂API中的函数。要使用这些函数构建应用程序,请调用墨西哥人
使用特定于发行版的选项-R2018a
。
当一个MEX函数返回控制到MATLAB®,它在输出参数中返回其计算结果mxArray
S包含在左边的参数中plhs []
。类创建的数组必须具有临时作用域,因此不要传递使用mexMakeArrayPersistent
函数plhs
。MATLAB破坏任何mxArray
由不在的MEX函数创建plhs
。方法释放在MEX函数中分配的任何内存mxCalloc
,mxMalloc
,或mxRealloc
功能。
一般来说,MathWorks®建议MEX函数销毁它们自己的临时数组并释放它们自己动态分配的内存。在源MEX文件中执行这种清理比依赖于自动机制更有效。这种方法与其他MATLAB API应用程序(mat文件应用程序、引擎应用程序和MATLAB编译器™生成的应用程序,没有任何自动清理机制。)
但是,不要破坏mxArray
在源MEX文件中:
传递给右边列表中的MEX文件
prhs []
在左侧列表中返回
plhs []
返回的
mexGetVariablePtr
用于创建一个结构
本节描述特定于内存管理的情况。我们建议您检查源MEX文件中的代码,以避免在以下情况下使用这些函数。有关更多信息,请参见自动清除MEX文件中的临时数组和持久mxArrays。有关内存问题的指导,请参见有效使用内存的策略。
潜在的内存管理问题包括:
不恰当地销毁mxArray
不要使用mxFree
摧毁…mxArray
。
例子
在下面的例子中,mxFree
不销毁数组对象。该操作释放了与数组相关的结构头,但MATLAB仍然像需要销毁数组对象一样运行。因此,MATLAB试图销毁数组对象,并在此过程中,试图再次释放其结构头:
mxArray *temp = mxCreateDoubleMatrix(1,1,mxREAL);…mxFree(临时);/*不正确*/
解决方案
调用mxDestroyArray
而不是:
mxDestroyArray(临时);/*正确*/
错误地构建单元格或结构mxArray
不要打电话mxSetCell
或mxSetField
变异与prhs []
作为成员数组。
例子
在下面的示例中,当MEX文件返回时,MATLAB将破坏整个单元格数组。由于这包括单元格的成员,因此这隐式地破坏了MEX文件的输入参数。这可能会导致一些奇怪的结果,通常与调用者工作区的损坏有关,如果使用的右侧参数是临时数组(例如,字面量或表达式的结果):
myfunction('hello') /* myfunction是您的MEX文件和代码的名称/*包含以下内容:*/ mxArray *temp = mxCreateCellMatrix(1,1);…mxSetCell(temp, 0, prhs[0]);/*不正确*/
解决方案
复制右边的论点mxDuplicateArray
然后用那个拷贝作为参数mxSetCell
(或mxSetField
变异)。例如:
mxSetCell(temp, 0, mxDuplicateArray(prhs[0]));/*正确*/
创建临时对象mxArray
资料不正确
不要打电话mxDestroyArray
在一个mxArray
它的数据不是由API例程分配的。
例子
如果你打电话mxSetDoubles
,mxSetComplexDoubles
,或指定未分配的内存的任何类型化数据访问函数mxCalloc
,mxMalloc
,或mxRealloc
作为预期的数据块(第二个参数),然后当MEX文件返回时,MATLAB尝试释放指向真实数据和虚构数据(如果有的话)的指针。因此,在本例中,MATLAB试图从程序堆栈中释放内存:
mxArray *temp = mxCreateDoubleMatrix(0,0,mxREAL);双数据[5]= {1,2,3,4,5};…mxSetM (temp, 1);mxSetN(临时、5);mxSetDoubles(临时、数据);/*不正确*/
解决方案
而不是使用mxSetDoubles
要设置数据指针,请创建mxArray
使用合适的尺寸和用途memcpy
返回的缓冲区中复制堆栈数据mxGetDoubles
:
mxArray *temp = mxCreateDoubleMatrix(1,5,mxREAL);双数据[5]= {1,2,3,4,5};…memcpy(mxGetDoubles(temp), data, 5*sizeof(double));/*正确*/
造成潜在的内存泄漏
在版本5.2之前,如果您创建了mxArray
使用API创建例程之一,然后覆盖指向数据的指针mxSetDoubles
, MATLAB仍然释放了原有的内存。MATLAB不再释放内存。
例如:
pr = mxCalloc(5*5, sizeof(double));…plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL);mxSetDoubles (plhs[0]、公关);/*不正确*/
现在泄漏5*5*8字节的内存,其中8字节是a的大小双
。
您可以通过更改代码来避免内存泄漏:
plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL);pr = mxGetDoubles(plhs[0]);…<将数据加载到数据库>
或者:
pr = mxCalloc(5*5, sizeof(double));…plhs[0] = mxCreateDoubleMatrix(5,5,mxREAL);mxFree (mxGetDoubles (plhs [0]));mxSetDoubles (plhs[0]、公关);
第一种解决方案更有效。
在使用时也会发生类似的内存泄漏mxSetDoubles
,mxSetComplexDoubles
,mxSetIr
,mxSetJc
,或任何数值类型的数据访问函数。您可以通过更改本节中描述的代码来避免内存泄漏。
不当破坏建筑物
对于结构,必须调用mxDestroyArray
只在结构上,而不是字段数据数组上。结构中的字段指向所使用的数组中的数据mxSetField
或mxSetFieldByNumber
。当mxDestroyArray
破坏结构,它尝试遍历自身并释放所有其他数据,包括数据数组中的内存。如果你打电话mxDestroyArray
在每个数据数组上,相同的内存被释放两次,这可能会破坏内存。
例子
下面的示例创建了三个数组:一个结构数组aStruct
还有两个数据数组,myDataOne
和myDataTwo
。字段名一个
中数据的指针myDataOne
,以及字段名两个
中数据的指针myDataTwo
。
mxArray * myDataOne;mxArray * myDataTwo;mxArray * aStruct;Const char *fields[] = {"one", "two"};myDataOne = mxCreateDoubleScalar(1.0);mydatattwo = mxCreateDoubleScalar(2.0);aStruct = mxCreateStructMatrix(1,1,2,fields);mxSetField(aStruct, 0, "one", myDataOne);mxSetField(aStruct, 1, "two", mydatattwo);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", mydatattwo);mxDestroyArray (aStruct);
在c++类析构函数中销毁内存
不要使用mxFree
或mxDestroyArray
函数中使用的类的c++析构函数。如果mex -函数抛出错误,MATLAB将清理mex文件变量,如自动清除MEX文件中的临时数组。
如果发生导致对象超出作用域的错误,MATLAB将调用c++析构函数。直接在析构函数中释放内存意味着MATLAB和析构函数释放相同的内存,这可能会破坏内存。