6

我们一直在与从 Matlab 编译器创建的库进行交互。我们的问题与从库返回的数组有关。

一旦我们完成了数组,我们想释放内存,但是这样做会导致偶尔的分段错误。

这是 Matlab 库 ( bugtest.m)::

function x = bugtest(y)

x = y.^2;

这是我们用来构建它的命令(创建libbugtest.so, 和libbugtest.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% 的时间内崩溃。

当我们取出那条有问题的线时,我们无法使其崩溃。

但是,当不包括此行时,内存使用量会逐渐增加。

从我们所做的研究来看,似乎我们应该破坏返回的数组,如果没有,我们如何阻止内存泄漏?

谢谢。

4

3 回答 3

1

好的,我知道这现在有点老了,但如果它有助于澄清任何路过的人......

Amro 提供了最相关的信息,但为了扩展它,如果您不按实际情况调用该mxDestroyArray函数,那么您将泄漏内存,因为您已将输出设置为NULL,因此 mlf 函数不会尝试调用mxDestroyArray. 这样做的必然结果是,如果您调用mxDestroyArray了 AND 然后尝试调用 mlf 函数output并且不为 NULL,那么 mlf 函数将尝试调用mxDestroyArrayon output。那么问题是output指向什么?output将其传递给后会发生什么,这是一个黑暗的角落mxDestroyArray。我会说这是一个没有根据的假设,它被设置为NULL;当然没有记录mxDestroyArray将其参数设置为NULL. 因此,我怀疑正在发生的事情是在您致电之间mxDestroyArray和重新执行 mlf 函数的代码,其他东西已经分配了指向的内存output,所以你的 mlf 函数试图释放属于其他东西的内存。瞧,段错误。当然,这只有在重新分配内存时才会发生。有时你会很幸运,有时不会。

黄金法则是,如果您mxDestroyArray为要重复使用的东西而调用自己,请在NULL之后立即将指针设置为。无论如何,您只需要在函数结束时销毁东西,因为您可以安全地在 mlf 调用中重用输出变量。

盖伊

于 2013-09-12T15:29:39.033 回答
0

几点注意事项:

  • 我没有singleCompThread在允许的选项列表中看到mclInitializeApplication.

  • 编译 C 程序的推荐方法是动态链接已编译的库:

    mbuild -v -I. bug_destroyarray.c -L. -lbugtest
    
  • 在您的 C 程序的顶部,只需包含生成的头文件,它将依次包含其他头文件。通过查看生成的标头,它具有:

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

    我不知道这条pragma行的确切含义,但也许它对 GCC 编译器很重要。

  • 两个 mlx/mlf 生成的函数都返回布尔值的事实是未记录的。但是查看头文件,两个签名确实返回 a bool

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

我试过你的代码,它工作得很好,没有段错误。由于我无法访问计算机集群,因此我的测试仅在我的本地计算机上完成(带有 R2013a 的 WinXP)。

我必须删除两个 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
于 2013-05-28T17:00:27.603 回答
0

感谢Amro的详细回复。

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

以下解决了我们的 seg-faulting 问题:

  • 不要output = NULL在每次迭代时设置,而是在循环外执行一次。
  • 不要mxDestroyArray(output)在循环内调用,参考:here

我们的误解是(似乎)您应该重用mxArray传递给 MATLAB 函数的指针。因为我们需要小心重用这个指针,所以这让我们的事情变得有点麻烦。

但是,内存是完全稳定的,从那以后我们还没有发生过崩溃。

于 2013-05-29T02:19:51.267 回答