【问题标题】:memory management problem in mexFunctionmexFunction 中的内存管理问题
【发布时间】:2010-10-28 19:20:37
【问题描述】:

我正在读取一个二进制数据文件,该文件是通过在 Matlab m-file 中调用以下行来编写的:

disp(sprintf('template = %d', fwrite(fid, template_1d, 'uint8')));

AFAIK,uint8 与 BYTE、unsigned char 和 unsigned short 类型的大小相同。因此,我在 Matlab 调用的 mexfunction 中实例化的 C++ 类中的文件读取方法中编写了以下代码:

template1D = (unsigned short*) malloc(Nimgs*sizeof(unsigned short)); printf("template1D = %d\n", fread(template1D, sizeof(unsigned short), Nimgs, dfile));

以下是我如何在类析构函数的辅助函数中释放这个成员变量:

免费((无效*)模板1D);

在主 mexfunction 中,当我没有通过调用 mexMakeMemoryPersistent() 函数在 mex 函数完成后将类对象实例化为持久存在内存中时,template1D 会被正确清除,而不会来自 Matlab 的分段错误消息。但是,如果我确实将类实例化为在内存中保持如下:

如果 (!dasani) { dasani = 新的 NeedleUSsim; mexMakeMemoryPersistent((void*) dasani); mexAtExit(ExitFcn); }

ExitFcn 为:

无效退出Fcn() { 删除dasani; }

然后当我在 free((void*) template1D); 行时,Matlab 给我一个关于分段错误的错误消息。我检查了内存大小,它们似乎是一致的。对于 malloc/calloc/free 函数,当我将 C++ 项目作为 Matlab mex 函数执行时,我使用的是 Matlab 的 mxMalloc/mxCalloc/mxFree 函数。

根据这个描述,你对我有什么进一步的建议来解决这个问题并确保将来不会发生这种情况(或者至少知道将来如何处理类似的问题)?

提前致谢。

--------------添加------ ------------------------------------

以下代码块基本上显示了我的 mex 文件的 jists。 mex 文件基本上是在 Matlab 中运行并从带有一些 Matlab 头文件的 C/C++ 代码编译的可执行文件。

无效退出Fcn() { 删除dasani; } void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { needle_info 引脚; // 检查 i/o 的数量是否正确 如果 (nrhs != NUM​​IN) { mexErrMsgTxt("输入参数的数量无效"); } 否则如果 (nlhs != NUM​​OUT) { mexErrMsgTxt("无效的输出参数个数"); } // 检查输入是否不复杂 如果(mxIsComplex(针)) { mexErrMsgTxt("输入必须是非复数标量整数。"); } // 检查针信息的尺寸是否有效 int needlerows, needlecols; needlerows = mxGetM(NEEDLE); needlecols = mxGetN(NEEDLE);
if (needlerows < 1 || needlecols < 6)
{ mexErrMsgTxt("针信息的尺寸无效"); } 浮动 *needlePoint, *yPoint ; // 获取当前针信息 // 变量的顺序总是如下: // r, theta, l, rho, alpha, beta needlePoint = (float*) mxGetData(NEEDLE) ; pin.r =针点[0]; pin.theta = needlePoint[1]; pin.l =针点[2]; pin.rho =针点[3]; pin.alpha =针点[4]; pin.beta = needlePoint[5]; //// 读取文件输入 **//如果(!dasani) //{ // dasani = new NeedleUSsim; // mexMakeMemoryPersistent((void*) dasani); // mexAtExit(ExitFcn); //} dasani = 新的 NeedleUSsim; 删除dasani;** // 现在发送一个无用的输出(如果在概念上不需要,请去掉它 plhs[0] = mxCreateNumericMatrix(1,1,mxSINGLE_CLASS,mxREAL) ; yPoint = (float*) mxGetData(plhs[0]) ; *yPoint = 1; }

如果用户从命令行或 m 文件脚本的任何位置调用“mexfunction”,此代码将在构建/编译后运行。由“**”包围的 sn-p(当我试图将 sn-p 加粗时)是我正在研究的问题。从第二次看 sn-p,我可能正在为 dasani 指针分配与 Matlab 内存不同的内存(因为内存的范围仅限于 C++ mex 函数,而另一个内存空间的范围可见到 Matlab 程序)。否则,我不确定为什么 Matlab 会抱怨这个问题。

【问题讨论】:

  • (unsigned) short 通常是 2 个字节。
  • 您能否提供更多代码以及如何使用它?如果您能详细解释一下 c++ 和 matlabs 如何协同工作,那就太好了。什么时候以及为什么会发生什么?只是一个简单的列表“1。类是在blabla中创建的”等
  • uint8 和 unsigned char 类型都是 1 字节(8 位),而 unsigned short 是 2 字节(16 位)。 FREAD 的文档包含您在读取和写入文件时可能使用的各种数据类型的列表:www.mathworks.com/access/helpdesk/help/techdoc/ref/fread.html。
  • 我想对类型进行更正。我用 unsigned char 而不是 unsigned short 测试了程序。 unsigned short 只是最新的 hack 努力,但没有奏效,这与使用 unsigned char 相同。
  • 好吧,我猜 dasani 是一些全局指针。 matlab 在哪里使用/使用该指针?我只是看到你的函数调用 new 来分配 NeedleUSsim 类的实例。另外,这个 mex 文件。是matlab编译的还是其他c++编译器编译的?

标签: c++ matlab


【解决方案1】:

MEX API 支持 C 和 C++。因为 C 没有 try/catch 或析构函数,所以 C MEX 函数无法在发生错误时直接清理内存。因此,MATLAB 在内部列表上跟踪内存分配例程(mxMalloc、mxCalloc、mxRealloc、mxFree 和所有返回 mxArrays 的 mxCreate* 函数)的结果。如果在 MEX 函数执行期间发生错误(通过直接调用 mexErrMsgIdAndTxt 或使用 mexEvalString 之类的东西来调用出现错误的 MATLAB 代码),则 MATLAB 将自动释放任何基于 mx 分配的内存。但是,当 MEX 函数正常终止时,MATLAB 将 还释放由 MEX 函数分配的任何基于 mx 的内存。在析构函数出现之前,这对 MEX 作者来说是一种便利,尽管在现代 C++ 世界中它会变得非常烦人。

有时,就像这个问题一样,您不希望 MATLAB 自动释放内存。在这种情况下,您必须对 mxArrays 使用 mexMakeMemoryPersistent 或 mexMakeArrayPersistent。

只有在最初使用 mxMalloc、mxCalloc 或 mxRealloc 分配的情况下,才应该传递指向 mexMakeMemoryPersistent 的指针。所以这段代码

dasani = new NeedleUSsim;
mexMakeMemoryPersistent((void*) dasani);

大写“B”不好,除非您重载了 NeedleUSsim::operator new() 以使用 mxMalloc,我不建议这样做。但是,如果 dasani 的字段是使用 mxMalloc 等分配的,那么您希望将这些字段传递给 mexMakeMemoryPersistent。如果可能的话,我建议在 NeedleUSsim 构造函数中执行类似的操作,以使其靠近 mxMalloc 调用。

【讨论】:

    【解决方案2】:

    感觉是 mexMakeMemoryPersistent() 造成了所有这些麻烦。我想你必须用它来指示matlab一旦完成就不要删除内存。但是matlab为什么要删除dasani指针呢?该指针是如何提供给 matlab 的,matlab 需要它做什么?

    【讨论】:

    • 我发现了问题所在,这与我如何实现 C++ 类没有任何关系。这与我没有将一些成员变量设置为持久性有关,除了将类设置为持久性之外,导致调用析构函数时这些成员变量的内存超出范围。
    【解决方案3】:

    除了使 dasani 成为持久指针之外,我还需要使其具有 mxMalloc/mxCalloc 分配的内存的成员变量也保持持久,例如:

    如果 (!dasani) { dasani = 新的 NeedleUSsim; mexMakeMemoryPersistent((void*) dasani->tplL); mexMakeMemoryPersistent((void*) dasani->tplR); mexMakeMemoryPersistent((void*) dasani->tplRho_deg); mexMakeMemoryPersistent((void*) dasani->tplAlpha_deg); mexMakeMemoryPersistent((void*) dasani->tplBeta_deg); mexMakeMemoryPersistent((void*) dasani->hashTb); mexMakeMemoryPersistent((void*) dasani->template1D); mexAtExit(ExitFcn); }

    使用如图所示的析构函数:

    void NeedleUSsim::Deallocate() { 免费((无效*)tplR);免费((无效*)tplL); 免费((无效*)tplRho_deg);免费((无效*)tplAlpha_deg); 免费((无效*)tplBeta_deg); 免费((无效*)hashTb); 免费((无效*)模板1D); }

    【讨论】:

    • 好!太糟糕了,我无法为你解决它:) 但最好还是自己找到原因。现在继续并接受您自己的答案作为您问题的解决方案。 15 分 :)
    • 不幸的是,我认为您不会因为接受自己的答案而获得 15 分。但是,我认为您仍然可以将答案标记为“已接受”获得 2 分,即使它是您的答案。
    • 我认为如果超过一定数量的用户对我的答案投票,我只能得到 15 分,我不知道是否会这样。无论如何,我在解释答案时遇到问题,但又不会在内容方面做得过火。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-31
    • 2017-08-02
    • 1970-01-01
    • 2023-03-24
    相关资源
    最近更新 更多