MATLAB与C语言内存管理机制存在显著差别。MATLAB采用自动内存释放机制,即在M文件或MEX文件中,内存的分配与释放,主要由MATLAB的解释器来自动完成。但在C语言程序中,内存的分配与释放由程序员编写代码来完成。因此,在MATLAB调用C程序的MEX文件中,内存管理仍显得十分重要。下面分别介绍MEX文件中内存分配与释放函数。
(1) mxMalloc
void *mxMalloc(size_t n);
参数:n 需分配的字节数;
返回:若分配成功,则返回一个指向所分配动态内存起始地址的指针;否则,终止MEX流程并返回MATLAB。
说明:mxMalloc函数自动分配n字节的连续内存空间,并在MATLAB内存管理器中注册返回堆栈入口(returned heap space)。MATLAB内存管理器有MEX文件中,所有由mxMalloc函数分配的内存注册清单,当MEX文件执行完毕或意外中止时,流程返回MATLAB前,MATLAB内存管理器将自动释放该清单上的所有内存空间。
内存释放函数:void mxFree(void *ptr);
(2) mxCalloc
void *mxCalloc(size_t n, size_t size);
参数:n 需分配的元素个数;
size 所分配每一元素字节数,通常由sizeof()函数取得。
返回:若分配成功,则返回一个指向所分配动态内存起始地址的指针;否则,终止MEX流程并返回MATLAB。
说明:mxCalloc函数自动分配n*size字节的连续内存空间,并将这n个元素初值均赋为0,同时也在MATLAB内存管理器中注册返回堆栈入口(returned heap space)。MATLAB内存管理器有MEX文件中,所有由mxCalloc函数分配的内存注册清单,当MEX文件执行完毕或意外中止时,流程返回MATLAB前,MATLAB内存管理器将自动释放该清单上的所有内存空间。
内存释放函数:void mxFree(void *ptr);
(3)mxRealloc
void *mxRealloc(void *ptr, size_t size);
参数:ptr 需重新分配内存的指针;
size 需重新分配内存的字节数。
返回:若分配成功,则返回一个指向所分配动态内存起始地址的指针;否则,返回0。
说明:mxRealloc函数对ptr重新分配内存,即使操作失败,也应进行内存释放。否则,易产生内存泄漏。
内存释放函数:void mxFree(void *ptr);
(4)mxCreate*函数
MEX文件中,MATLAB提供了众多的mxCreate函数来创建不同类型的mxArray数据类型对象。这些函数操作成功后,返回相应的内存地址(指针);否则,返回不同类型的错误信息。由mxCreate*函数创建的mxArray数据类型所占内存空间,均由mxDestroyArray()函数释放。
常用的mxCreate函数主要有如下几种。
①mxArray * mxCreateDoubleScalar (double value);
参数:value 所创建的mxArray数据类型(1行×1列)的初值;
返回:若操作成功,则返回一个指向所创建的mxArray数据类型(1行×1列)的指针;否则,,终止MEX流程并返回MATLAB。
说明:该函数与下述语句作用相同,均可返回一个指向1行×1列的mxArray类型指针。
a = mxCreateDoubleMATrix(1, 1, mxREAL);
*mxGetPr(pa) = value;
内存释放函数:void mxDestroyArray(mxArray *array_ptr);
②mxArray *mxCreateString(const char *str);
参数:str 所创建的mxArray类型的字符串(仅1行)的初值;
返回:若操作成功,则返回一个指向所创建的mxArray类型的字符串指针;否则,返回NULL。
内存释放函数:void mxDestroyArray(mxArray *array_ptr);
③mxArray *mxCreateNumericMATrix(int m, int n, mxClassID class, mxComplexity ComplexFlag);
参数:m 需创建的mxArray矩阵的行数;
n 需创建的mxArray矩阵的列数;
class 数据类型,取值为: mxDOUBLE_CLASS, mxSINGLE_CLASS, mxINT8_CLASS, mxUINT8_CLASS, mxINT16_CLASS, mxUINT16_CLASS, mxINT32_CLASS, mxUINT32_CLASS, mxINT64_CLASS, and mxUINT64_CLASS,分别对应双精度、单精度、8位整型、8位无符号整型、16位整型、16位无符号整型、32位整型、32位无符号整型、64位整型、64位无符号整型等数据类型;
ComplexFlag 取值为mxREAL 和 mxCOMPLEX,分别代表所创建的mxArray矩阵为实数型矩阵和复数型矩阵。
返回:若操作成功,则返回一个指向所创建的mxArray类型矩阵的指针;否则,终止MEX流程并返回MATLAB。
内存释放函数:void mxDestroyArray(mxArray *array_ptr);
④mxArray *mxCreateDoubleMATrix(int m, int n, mxComplexity ComplexFlag);
参数:m 需创建的mxArray矩阵的行数;
n 需创建的mxArray矩阵的列数;
ComplexFlag 取值为mxREAL 和 mxCOMPLEX,分别代表所创建的mxArray矩阵为实数型矩阵和复数型矩阵。
返回:若操作成功,则返回一个指向所创建的mxArray类型矩阵的指针;否则,终止MEX流程并返回MATLAB。
内存释放函数:void mxDestroyArray(mxArray *array_ptr);
⑤mxArray *mxCreateCellMATrix(int m, int n);
参数:m 需创建的mxArray矩阵的行数;
n 需创建的mxArray矩阵的列数。
返回:若操作成功,则返回一个指向所创建的cell mxArray类型的指针。否则,终止MEX流程并返回MATLAB。
内存释放函数:void mxDestroyArray(mxArray *array_ptr);
MEX文件内存分配与释放例子,可参见“h1.c”、“h2.c”和“h3.c”。在给MEX文件的输出参数plhs[]赋值,除各例中所采取赋值方式外,还可使用memcpy()函数或mxDuplicateArray()函数,进行数据拷贝。
“h1.c” 文件中,在使用plhs[0]=mxCreateDoubleMATrix(1,nlhs,mxREAL)给plhs[0]分配内存地址后,对应的内存数据拷贝memcpy()函数为:
lP= mxCalloc(nlhs,sizeof(double));
for(i=0;i<nlhs;i++)lP[i]=i*sum;
memcpy(mxGetPr(plhs[0]),lP,nlhs*sizeof(double));///使用内存数据拷贝函数memcpy()
mxFree(lP);
“h1.c” 文件中,在使用plhs[0]=mxCreateDoubleMATrix(1,nlhs,mxREAL)给plhs[0]分配内存地址后,对应的mxDuplicateArray()函数为:
mxArray lP0; ///定义mxArray类型的指针变量*lP0
lP0=mxCreateDoubleMATrix(1,nlhs,mxREAL); /////并对lP0分配内存地址
lP= mxCalloc(nlhs,sizeof(double));
for(i=0;i<nlhs;i++)lP[i]=i*sum;
memcpy(mxGetPr(lP0),lP,nlhs*sizeof(double)); /////采用内存拷贝函数将数据拷贝与lP0
plhs[0]=mxDuplicateArray(lP0); /////使用内存数据拷贝函数mxDuplicateArray()
mxFree(lP);
mxDestroyArray(lP0); ////////释放lP0
在MEX文件内存管理中,MATLAB还提供了内存变量保留机制,用户可以声明MEX文件中的变量或某一段内存为保留属性,方法是使用mexMakeArrayPersistent或mexMakeMemeoryPersistent。由于MATLAB内存自动释放机制不能释放用户申明的具保留属性的变量和内存段,在MEX整个文件过程甚至MEX文件终止后,这些被保留的变量和内存段一直不会被自动释放,用户可在整个MEX文件中使用这些变量和内存,但当MEX文件终止时,用户必须自己释放这些变量和内存段。为防止因MEX文件意外终止而导致操作进程不能执行用户编写的内存释放代码,MATLAB提供了mexAtEixt函数,该函数在MEX文件在内存中被清除时调用,因此,用户对申明了保留属性的变量和内存段的释放代码,一般通过该函数调用执行,以避免内存泄漏。
/////////////////////////////////////// mexAtEixt执行时调用的函数
void DeAllocPersistent()
{
mexPrintf("\n退出MEX文件,清除内存!\n");
mxDestroyArray(lP0);
mxFree(buf);
}
////////////////// 接口程序mexFunction/////////////////////////////////////
void mexFunction(int nlhs,mxArray *plhs[],int nrhs, mxArray *prhs[])
{
mxArray *lP0;
char *buf;
…………….
lP0=mxCreateDoubleMATrix(1,nlhs,mxREAL);
mexMakeArrayPersistent(lP0); ////// 申明lP0为保留属性
……………..
buf= mxMalloc(100);
mexMakeMemoryPersistent(buf); /////////// 申明buf 为保留属性
………………..
mexAtEixt(DeAllocPersistent); ////////////// MEX文件在内存中被清除时调用mexAtExit函数,
////// 一般一个MEX文件中只一个mexAtExit函数,若用户提供多个
////// mexAtExit函数时,MATLAB只调用最近的mexAtExit函数。
………………..
}
最后值得一提的mxDestroyArray(mxArray *array_ptr)函数,该函数不仅释放了array_ptr所指的mxArray数据的m行和n列空间,还释放了所有与之相关的诸如实部指针pr、虚部指针pi等内存地址。因此,对于MEX文件中的输出参数,一般不使用mxDestroyArray()函数来释放其内存,而由MATLAB的自动内存管理机制来释放。