MxDestroyArray call for mxArray objects returned from Matlab Compiler Runtime

We interacted with the library created from Matlab Compiler. Our problem is with the array returned from the library.

Once we are done with the array, we want to free up memory, however this leads to random segmentation errors.

Here is the Matlab library ( bugtest.m ):

 function x = bugtest(y) x = y.^2; 

Here is the command we used to create it (creating libbugtest.so and libbugtest.h ):

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

Here is our C testing program ( 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(); } 

This is how we compile the C program (create bug_destroyarray ):

 mbuild -v bug_destroyarray.c libbugtest.so 

We believe mxDestroyArray(output) is problematic.

To verify the failure, we run the following:

  • On each of 32 cluster nodes.
  • Run bug_destroyarray .
  • Monitor output for segmentation errors.

In approximately 10% of cases, a failure occurs. If this is independent by nodes, then you can assume that it falls by about 0.3% of the time.

When we take out this problematic line, we cannot cause it to crash.

However, memory usage gradually increases when this line is not included.

From our research, it seems that we should not destroy the returned array, if not, how do we stop the memory leak?

Thanks.

+6
source share
3 answers

Well, I know that now it's a little old-fashioned, but in case it helps clarify the situation for anyone passing by ...

Amro provides the most appropriate information, but expands if you do not call the mxDestroyArray function as you stand, then you will leak memory because you set the output to NULL and therefore the mlf function will not try to call mxDestroyArray . The consequence of this is that if you called mxDestroyArray AND then try to call the mlf function AND the output NOT NO, then the mlf function will try to call mxDestroyArray on output . The question then is what does output mean? This is a slightly dark corner that happens to output after passing it to mxDestroyArray . I would say that this is an unfounded assumption that it is set to NULL ; of course, he did not document that mxDestroyArray sets its argument to NULL . Therefore, I suspect what is happening between the fact that between your call to mxDestroyArray and the repeated execution of the mlf function, something else was allocated with the memory pointed to by output , and therefore your mlf function is trying to free memory for something else. Voila, seg fault. And, of course, this will happen only if the memory is redistributed. Sometimes you are lucky, sometimes not.

Golden rule: if you call mxDestroyArray yourself for what will be reused, immediately set the pointer to NULL . You still need to destroy things at the end of your function, since you can safely reuse output variables in mlf calls.

Guy

+1
source

A few notes:

  • I do not see singleCompThread in the list of allowed options for mclInitializeApplication .

  • The recommended way to compile your C program is to dynamically link to the compiled library:

     mbuild -v -I. bug_destroyarray.c -L. -lbugtest 
  • At the top of your C program, just add the generated header file, it will include other headers. From a look at the generated header, it has:

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

    I do not know the exact meaning of this pragma , but perhaps it matters with the GCC compilers.

  • The fact that as mlx / mlf generated functions return boolean values ​​is undocumented . But looking at the header files, both signatures do return a bool :

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

I tried your code and it works fine, without segfaults. Since I do not have access to a cluster of computers, my testing was performed only on my local machine (WinXP with R2013a).

I had to remove both MCR initialization options to work (in particular, nojvm caused a runtime error). Below is the full code with a few changes. It took about 10 seconds to start:

 #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; } 

Also, the compilation step is slightly different on Windows, since we statically refer to lib (which inserts a dummy for dynamically loading the DLL at run time):

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

Thanks for Amro's detailed answer.

We tried to change our compilation steps to recommended without success.

The following fix for the seg-faulting problem:

  • Do not set output = NULL at each iteration; instead, execute it outside the loop.
  • Do not call mxDestroyArray(output) inside the loop, link: here .

Our misunderstanding was that (it seems) you should reuse the mxArray pointers that you pass into the MATLAB functions. This makes things a little cumbersome on our side, as we need to be careful when reusing this pointer.

However, the memory is completely stable, and since then we have not had a glitch.

0
source

Source: https://habr.com/ru/post/945984/


All Articles