6

回到我们一直在与接口从MATLAB编译器创建一个图书馆。我们的问题与库中返回的数组有关。上mxArray调用mxDestroyArray对象从MATLAB编译器运行时

一旦我们与阵列完成,我们想释放内存,但是,这样做会导致偶尔的段故障。

这里是Matlab的库(bugtest.m)::

下面是我们用来构建它的命令(创建libbugtest.solibbugtest.h)::

mcc -v -W lib:libbugtest -T link:lib bugtest.m 

这里是我们的C测试程序(bug_destroyarray.c)::

#include <stdio.h> 
#include <stdlib.h> 

#include "mclmcrrt.h" 
#include "libbugtest.h" 

#define TESTS 15000 

int main(int argc, char **argv) 
{ 
    const char *opts[] = {"-nojvm", "-singleCompThread"}; 
    mclInitializeApplication(opts, 2); 
    libbugtestInitialize(); 

    mxArray *output; 
    mxArray *input; 
    double *data; 
    bool result; 
    int count; 

    for (count = 0; count < TESTS; count++) { 

     input = mxCreateDoubleMatrix(4, 1, mxREAL); 
     data = mxGetPr(input); data[0] = 0.5; data[1] = 0.2; data[2] = 0.2; data[3] = 0.1; 

     output = NULL; 
     result = mlfBugtest(1, &output, input); 
     if (result) { 
      /* HERE IS THE PROBLEMATIC LINE */ 
      /*mxDestroyArray(output);*/ 
     } 

     mxDestroyArray(input); 
    } 

    libbugtestTerminate(); 
    mclTerminateApplication(); 
} 

这里是我们如何编译C程序(创建bug_destroyarray)::

mbuild -v bug_destroyarray.c libbugtest.so 

我们认为mxDestroyArray(output)是有问题的。

我们运行下面的测试崩溃:

  • 在每个32个节点。
  • 运行bug_destroyarray
  • 监控分段故障的输出。

的时间大约10%有崩溃。如果这个节点在节点 之间是独立的,那么你可能会认为它大概会在0.3%的时间内崩溃。

当我们采取的是有问题的行,我们是无法导致崩溃。当不包括该行

然而内存使用情况逐渐增加。

从我们所做的研究看来,我们似乎是而不是应该销毁返回的数组,如果不是,我们如何阻止泄漏内存?

谢谢。

+0

你确定你有'mlfBugtest'的签名是否正确吗?该文档似乎表明'mlf'函数返回'void',而不是'bool'。 – wakjah

回答

0

的几个注意事项:

  • 我没有看到singleCompThread按照允许的选项mclInitializeApplication列表。

  • 编译C程序的recommended方式是动态针对编译库链接:

    mbuild -v -I. bug_destroyarray.c -L. -lbugtest 
    
  • 在你的C程序的顶部,仅仅只包含生成的头文件,它会包括其他头反过来。通过观察生成的头,它具有:

    #pragma implementation "mclmcrrt.h" 
    #include "mclmcrrt.h" 
    

    我不知道这个pragma线的确切含义,但也许它与GCC编译问题的..

  • 两个MLX/MLF产生的事实函数返回布尔值为undocumented。但看的头文件,这两个签名确实返回bool

    extern bool mlxBugtest(int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[]); 
    extern bool mlfBugtest(int nargout, mxArray** x, mxArray* y); 
    

我想你的代码,它工作得很好,没有段错误。由于我没有访问计算机集群,我的测试只能在本地计算机上完成(WinXP with R2013a)。

我不得不删除两个MCR初始化选项使其工作(特别是nojvm导致运行时错误)。以下是完整的代码,稍作修改。前后花了10秒运行:

#include <stdio.h> 
#include <stdlib.h> 
#include "libbugtest.h" 

#define TESTS 15000 

int main() 
{ 
    mxArray *output, *input; 
    double *data; 
    int count; 
    bool result; 

    if(!mclInitializeApplication(NULL,0)) { 
     fprintf(stderr, "Could not initialize the application.\n"); 
     return EXIT_FAILURE; 
    } 
    if (!libbugtestInitialize()) { 
     fprintf(stderr, "Could not initialize the library.\n"); 
     return EXIT_FAILURE; 
    } 

    for (count = 0; count < TESTS; count++) { 
     input = mxCreateDoubleMatrix(4, 1, mxREAL); 
     data = mxGetPr(input); 
     data[0] = 0.5; data[1] = 0.2; data[2] = 0.2; data[3] = 0.1; 

     output = NULL; 
     result = mlfBugtest(1, &output, input); 
     if (!result) { 
      fprintf(stderr, "call failed on count=%d\n", count); 
      return EXIT_FAILURE; 
     } 

     mxDestroyArray(output); output = NULL; 
     mxDestroyArray(input); input = NULL; 
    } 

    libbugtestTerminate(); 
    mclTerminateApplication(); 

    return EXIT_SUCCESS; 
} 

而且编译步骤是在Windows上有点不同,因为我们对导入库静态链接(这将插入一个存根动态加载运行时的DLL):

mbuild -v -I. bug_destroyarray.c libbugtest.lib 
0

感谢您的详细回复Amro。

我们尝试将我们的编译步骤改为推荐的步骤,但没有成功。

下固定我们的赛格断层问题:

  • 不要设置output = NULL在每次迭代,而不是循环外做一次。
  • 不要在回路内呼叫mxDestroyArray(output),参考:here

我们的误解是(看来)你应该重用mxArray指针,你传递给MATLAB函数。这使我们的工作稍微麻烦一些,因为我们需要小心重复使用这个指针。

但是,内存是完全稳定的,我们从此没有崩溃。

+0

我觉得你在第二点上让人困惑。链接到的页面是在MEX函数的上下文中(您不想将左侧返回给MATLAB)。至于另一点,[docs](http://www.mathworks.com/help/compiler/matlab-compiler-generated-interface-functions.html#f2-1008549)明确指出:“如果输出变量为传入一个mlf函数不是NULL,mlf函数将尝试使用mxDestroyArray释放它们。“所以,你应该有任何区别,你是否明确地释放自己的记忆或让mlf功能做 – Amro

+0

啊好的,谢谢你的解释。我不应该说过,只是意味着不在循环中。这一切都有道理,并且正在正常工作。干杯。 – user2427155

1

好吧,我知道现在这个是有点老了,但万一它有助于澄清事情的人路过...

荷银提供最相关的信息,但在它的扩大,如果你不”根据情况调用mxDestroyArray函数,那么您将泄漏内存,因为您已将输出设置为NULL,因此mlf函数不会尝试调用mxDestroyArray。这样的推论是,如果您调用mxDestroyArray,然后尝试调用mlf函数并且output不为NULL,那么mlf函数将尝试在output上调用mxDestroyArray。那么问题是output指向什么?在output传递给mxDestroyArray后,发生了什么变化。我会说这是一个毫无根据的假设,它被设置为NULL;当然没有记录mxDestroyArray将其参数设置为NULL。因此,我怀疑在你拨打mxDestroyArray和重新执行mlf函数的代码之间发生了什么,其他的东西已经分配给output指向的内存,所以你的mlf函数试图释放属于别的东西的内存。 Voila,seg故障。当然,这只会在内存重新分配时才会发生。有时你会很幸运,有时候不会。

黄金法则是,如果您自己调用mxDestroyArray来处理将要重用的内容,请立即将指针设置为NULL。无论如何,你只需要在函数结尾处销毁东西,因为你可以在mlf调用中安全地重用输出变量。

盖伊

+0

我希望我能为此找到一个很好的参考。我能找到的最好的[集成C共享库](http://www.mathworks.com/help/compiler/c-shared-library-target.html) –