Using RAM by mex-function

Something strange occurs when I try to transfer matrices to mex-function. When matrices size is not big the mex-function perform well, but if size of my matrices about 500*500 and more matlab will crush without any message. The terminal reports about a segmentation fault.
#include "mex.h"
#include <iostream>
#include "CFullVec.h"
double GAMMA, Mnuclon;
int NR, NZ;
void mexFunction(int nlhs, mxArray *plhs[], // output to ML
int nrhs, const mxArray *prhs[]) // input to C++
{{
double *parGas, *parGrid, *parTime;
size_t mrows, ncols;
std::cout << "zdfgbDSFB" << std::endl;
// check nb of gas parameters
mrows = mxGetM(prhs[0]);
ncols = mxGetN(prhs[0]);
if(mrows!=2 || ncols!=1){
mexErrMsgIdAndTxt("MATLAB:mexcpp:nargin", "Incorrect vector of the gas parameters");
}
// check nb of grid parameters
mrows = mxGetM(prhs[1]);
ncols = mxGetN(prhs[1]);
if(mrows!=6 || ncols!=1){
mexErrMsgIdAndTxt("MATLAB:mexcpp:nargin", "Incorrect vector of the grid parameters");
}
// check nb of time parameters
mrows = mxGetM(prhs[2]);
ncols = mxGetN(prhs[2]);
if(mrows!=3 || ncols!=1){
mexErrMsgIdAndTxt("MATLAB:mexcpp:nargin", "Incorrect vector of the time parameters");
}
parGas=mxGetPr(prhs[0]);
double GAMMA = parGas[0];
double Mnuclon = parGas[1];
parGrid=mxGetPr(prhs[1]);
NR = static_cast<int>( (parGrid[1]-parGrid[0])/parGrid[2] ) + 1;
NZ = static_cast<int>( (parGrid[4]-parGrid[3])/parGrid[5] ) + 1;
parTime=mxGetPr(prhs[2]);
const int ST = static_cast<int>( parTime[0]/parTime[1] );
const int CVAR = static_cast<int>( parTime[0]/parTime[2] );
// check data dimensions
for(int i=3; i<=3+7; i++){
mrows = mxGetM(prhs[i]);
ncols = mxGetN(prhs[i]);
//std::cout << i << ' ' << mrows << ' ' << ncols << std::endl;
if(mrows!=NR+2 || ncols!=NZ+2){
// mexErrMsgIdAndTxt("MATLAB:mexcpp:nargin", "Incorrect array of initial data");
}
}
double *rho, *Vr, *Vp, *Vz, *Br, *Bp, *Bz, *T; // these pointers are used both to input and to output
// assign pointers to input
rho=mxGetPr(prhs[3]); Vr=mxGetPr(prhs[4]); Vp=mxGetPr(prhs[5]); Vz=mxGetPr(prhs[6]);
Br=mxGetPr(prhs[7]); Bp=mxGetPr(prhs[8]); Bz=mxGetPr(prhs[9]); T=mxGetPr(prhs[10]);
FullVec U[NR+2][NZ+2];
// something else....
The error happens in the last three lines. Also if the declaration of U[NR+2][NZ+2] is deleted the error may not happen. Therefore I think this error is associated with RAM, but the matrices take not more than 40-50 MB RAM and U[NR+2][NZ+2] takes about the same.
I use linux mint 64-bit. I add -largeArrayDims during compilation. Could you tell me, what is going wrong?

 Accepted Answer

James Tursa
James Tursa on 3 Mar 2017
Edited: James Tursa on 7 Mar 2017
I haven't looked over your code in any detail, but this line definitely raises a red flag:
FullVec U[NR+2][NZ+2];
U is a local array variable, so its memory will be allocated from the stack, not the heap. While 50MB is not a particularly large number when compared to the heap, it is a potentially huge number when compared to the stack memory available. I can easily see where this could work without issue for small sizes, but blow the stack and crash MATLAB for a 50MB array. The solution is to never allocate variables of anywhere near this size off of the stack ... always allocate off of the heap instead. That means you need to allocate the memory for U using mxMalloc or mxCalloc since that memory comes from the heap. And since you are using the double bracket syntax [ ][ ] for accessing the elements, you will either need to give that syntax up and do your own manual indexing with single bracket [ ] notation, or you will need to allocate U in two stages (one for the first [ ] stuff and one for the second [ ] stuff). Let me know if you need help doing that. E.g., see this link for some example code on using double bracket [ ][ ] syntax with heap allocated memory:
https://www.mathworks.com/matlabcentral/answers/309434-matlab-crashing-when-evaluating-mex

More Answers (1)

Ilya Kalash
Ilya Kalash on 5 Mar 2017
Edited: Ilya Kalash on 6 Mar 2017
Thank you a lot, James. Your answer is very detailed and useful.
So, I have made some changes:
// assign pointers to input
int nbAll = (NR+2)*(NZ+2);
double *rho = (double*)mxCalloc( (mwSize)nbAll,sizeof(double)); rho=mxGetPr(prhs[3]);
double *Vr = (double*)mxCalloc( (mwSize)nbAll,sizeof(double)); Vr=mxGetPr(prhs[4]);
double *Vp = (double*)mxCalloc( (mwSize)nbAll,sizeof(double)); Vp=mxGetPr(prhs[5]);
double *Vz = (double*)mxCalloc( (mwSize)nbAll,sizeof(double)); Vz=mxGetPr(prhs[6]);
double *Br = (double*)mxCalloc( (mwSize)nbAll,sizeof(double)); Br=mxGetPr(prhs[7]);
double *Bp = (double*)mxCalloc( (mwSize)nbAll,sizeof(double)); Bp=mxGetPr(prhs[8]);
double *Bz = (double*)mxCalloc( (mwSize)nbAll,sizeof(double));Bz=mxGetPr(prhs[9]);
double *T = (double*)mxCalloc( (mwSize)nbAll,sizeof(double));T=mxGetPr(prhs[10]);
FullVec **U = (FullVec**)mxCalloc((mwSize)(NR+2), sizeof(FullVec*));
for(int i=0; i<NR+2; i++) U[i] = (FullVec*)mxCalloc((mwSize)(NZ+2), sizeof(FullVec));
// DOING SMT
for(int i=0; i<NR+2; i++) mxFree(U[i]);
mxFree(U); U=NULL;
//mxFree(rho); mxFree(Vr); mxFree(Vp); mxFree(Vz);
//mxFree(Br); mxFree(Bp); mxFree(Bz); mxFree(T);
//rho=NULL; Vr=NULL; Vp=NULL; Vz=NULL;
//Br=NULL; Bp=NULL; Bz=NULL; T=NULL;
The part with the dynamic array U works well (i've been testing it). But the command mxFree() for rho..T spoils anything.
With the command the mex-function could be run 2-3 times and after that matlab crashes (it depends on sizes of arrays). Also if I do command clear in matlab's command line after runing the mex-function matlab will crash too.
I've tried to make null pointer assignment before the deallocating and to avoid that assignment. It hasn't led to anything.
Without the two lines with mxFree() (or without last four lines) the program works well (such a paradox!).

2 Comments

You almost got this correct, but not quite. Let me pick apart these lines of code to show you the crashing problem you have:
(1) double *rho = (double*)mxCalloc( (mwSize)nbAll,sizeof(double));
(2) rho = mxGetPr(prhs[3]);
:
(3) mxFree(rho);
Line (1) allocates memory from the heap via mxCalloc and assigns that memory address to rho. This is not what you really needed to do, but in and of itself causes no immediate harm.
Line (2) then turns around and wipes out the value you just stored in rho via (1) with another different memory address from mxGetPr. So you obliterated the heap address from (1) by overwriting it with another different address from (2). This creates a memory leak since that mxCalloc memory address is now lost to you as you have no handle to it saved in any variable. In particular, you will not be able to manually mxFree it because you have lost its value. (It turns out that MATLAB's garbage collection will cover you in this case and free the memory when the mex routine returns control to the caller, but it is not good programming practice to rely on this).
Line (3) frees the data pointer (the one you got via mxGetPr) that is currently attached to an existing mxArray. This is very bad since that mxArray is now in an invalid state. Any action that uses this mxArray and tries to access its data will be using an invalid pointer and likely result in a MATLAB crash. Even simply clearing this mxArray can crash MATLAB since the equivalent of mxFree will be called with an invalid pointer as input.
So, to fix this you need to get rid of lines (1) and (3). If you are trying to access the data area of an existing mxArray via mxGetPr (and friends), do not allocate any memory for this pointer ahead of time, and do not attempt to free it later. The data memory will automatically be freed whenever its associated mxArray gets destroyed, so you don't need to worry about that part.
Finally, I will point out that your current method of allocating the U[i] stuff will not guarantee that the actual data for all of these rows will be contiguous. I.e., one row will not necessarily be immediately adjacent to the next row in memory because they were allocated using separate mxCalloc calls. This may not be important to you in your downstream code, but I thought I would point it out to you. If you want the data to be contiguous in memory, use the technique I show in the link I provided above.
It really works. Thanks.

Sign in to comment.

Categories

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!