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?

 채택된 답변

James Tursa
James Tursa 2017년 3월 3일
편집: James Tursa 2017년 3월 7일

0 개 추천

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

추가 답변 (1개)

Ilya Kalash
Ilya Kalash 2017년 3월 5일
편집: Ilya Kalash 2017년 3월 6일

0 개 추천

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

James Tursa
James Tursa 2017년 3월 6일
편집: James Tursa 2017년 3월 6일
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.
Ilya Kalash
Ilya Kalash 2017년 3월 9일
It really works. Thanks.

댓글을 달려면 로그인하십시오.

카테고리

도움말 센터File Exchange에서 Write C Functions Callable from MATLAB (MEX Files)에 대해 자세히 알아보기

질문:

2017년 3월 3일

댓글:

2017년 3월 9일

Community Treasure Hunt

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

Start Hunting!

Translated by