Memory leak in mex file
Show older comments
I am working with a mex file that was leaking memory due to code below. I have tried clearing arrays using mxDestroyArray but with that Matlab got stuck:
// create cell array for returning classification result
plhs[0] = mxCreateCellMatrix((int)leafIndicesPerTree.size(),1);
// information about structure fields
mwSize dims[2] = {1,1};
const char *field_names[] = {"class","distrib","codebase","votes"};
// loop through trees and determine the winning class for each sampling point
for(int t=0; t<leafIndicesPerTree.size();t++){
//allocate matlab vector which has as many entries as there were sampling points in the test image
mxArray* currentTree = mxCreateStructArray(2, dims, 4, field_names);
mxArray* classArray = mxCreateDoubleMatrix(testData.Count(),1,mxREAL);
mxArray* distribArray = mxCreateDoubleMatrix(testData.Count(),numClasses,mxREAL);
mxArray* votesCell = mxCreateCellMatrix(testData.Count(),1);
mxArray* codebaseCell = mxCreateCellMatrix(testData.Count(),1);
// loop through all the sampling positions
for (unsigned int i=0; i<testData.Count(); i++) {
// determine classification result (bin with maximal value)
int leafIndex=leafIndicesPerTree[t][i];
StatisticsProvider result=forest->GetTree(t).GetNode(leafIndex).TrainingDataStatistics;
int winnerClass = 0;
double maxDistrib = -1;
for(int j=0;j<numClasses;j++){
if(result.getProbability(j) > maxDistrib){
winnerClass = j;
maxDistrib = result.getProbability(j);
}
}
// write winner class
double* arrayValue = mxGetPr(classArray);
arrayValue[i] = winnerClass;
// write distribution
arrayValue = mxGetPr(distribArray);
for(int c=0;c<numClasses;c++){
arrayValue[c*testData.Count()+i] = result.getProbability(c);
}
// if sampling point has been classified as foreground save votes and codebase
if(winnerClass > 0){
// get votes of winner class (votes only exist for foreground classes --> winnerClass-1)
std::vector<DataPoint> votes = result.getVotes(winnerClass-1);
// create matrix to store votes
// first column: x coordinate
// second column: y coordinate
// third column: z coordinate
// fourth column: image index
mxArray* codebaseArray = mxCreateDoubleMatrix((int)votes.size(),4,mxREAL);
double* codebaseArrayValue = mxGetPr(codebaseArray);
// create matrix to store votes
// for each vector to each object centroid there are three columns (x coordinate, y coordinate z coovotesrdinate)
mxArray* votesArray = mxCreateDoubleMatrix((int)votes.size(),(numClasses-1)*3,mxREAL);
double* votesArrayValue = mxGetPr(votesArray);
for(int v=0;v<votes.size();v++){
// extract codebase
codebaseArrayValue[v] = votes[v].getOrigPos().x+1;
codebaseArrayValue[votes.size()+v] = votes[v].getOrigPos().y+1;
codebaseArrayValue[2*votes.size()+v] = votes[v].getOrigPos().z+1;
codebaseArrayValue[3*votes.size()+v] = votes[v].getImageIndex()+1;
// extract votes
for(int c=0;c<(numClasses-1);c++){
votesArrayValue[c*3*votes.size()+v] = votes[v].getVote(c).x+1;
votesArrayValue[(c*3+1)*votes.size()+v] = votes[v].getVote(c).y+1;
votesArrayValue[(c*3+2)*votes.size()+v] = votes[v].getVote(c).z+1;
}
}
mxSetCell(codebaseCell,i,codebaseArray);
mxSetCell(votesCell,i,votesArray);
mxDestroyArray(codebaseArray);
mxDestroyArray(votesArray);
}
}
mxSetField(currentTree,0,"class",classArray);
mxSetField(currentTree,0,"distrib",distribArray);
mxSetField(currentTree,0,"votes",votesCell);
mxSetField(currentTree,0,"codebase",codebaseCell);
mxSetCell(plhs[0],t,currentTree);
mxDestroyArray(classArray);
mxDestroyArray(distribArray);
mxDestroyArray(votesCell);
mxDestroyArray(codebaseCell);
mxDestroyArray(currentTree);
}
Any idea why that could be happening?
Answers (1)
James Tursa
on 11 Mar 2016
Edited: James Tursa
on 11 Mar 2016
Sounds like you have two problems, a memory leak and MATLAB crashing. Let's clear up the MATLAB crashing first and then get back to your memory leak.
Your MATLAB crashes are caused by you doing mxDestroyArray on an mxArray that is part of a struct or cell array. You can't do that because it invalidates the memory inside the struct or cell array variable ... so when MATLAB tries to access the contents of the struct or cell array it accesses this invalid memory and bombs. Here is the basic behavior:
mxSetCell, mxSetField, and mxSetFieldByNumber have the following syntax:
void mxSetCell(mxArray *pm, mwIndex index, mxArray *pvalue);
void mxSetField(mxArray *pm, mwIndex index, const char *fieldname, mxArray *pvalue);
void mxSetFieldByNumber(mxArray *pm, mwIndex index, int fieldnumber, mxArray *pvalue);
The all do the following to pvalue:
1) Set the appropriate element of pm equal to pvalue (i.e., copy the address into the element spot ... this is not a deep copy of pvalue)
2) Change the type of pvalue to "SUB-ELEMENT" (i.e., one of the hidden fields in the mxArray variable itself gets changed to indicate it is part of a struct or cell array)
3) The address pvalue gets removed from the garbage collection list.
So the disposition of pvalue is now tied to the struct or cell array that it is now part of. When this struct or cell array gets deep destroyed, all of the elements (the mxArray variables that are the elements) get automatically deep destroyed as well.
Also, you cannot re-use a pvalue in multiple mxSetCell, mxSetField, or mxSetFieldByNumber calls because when MATLAB tries to deep destroy the struct or cell array it will try to destory the pvalue multiple times, causing a crash (accessing memory that was invalidated with the first destroy of pvalue). Now, this advice is based on the official API functions that are available to you. But in fact there is a way to re-use the pvalue mxArray variables inside of struct and cell arrays using non-standard methods (unofficial API functions or hacking into the mxArray) ... but I won't publish that info here since it is a bit off-topic to your problem.
BOTTOM LINE: Get rid of all those mxDestroyArray calls that are used on struct or cell array contents!
E.g.,
mxSetCell(codebaseCell,i,codebaseArray);
mxSetCell(votesCell,i,votesArray);
mxDestroyArray(codebaseArray); <-- This will crash MATLAB
mxDestroyArray(votesArray); <-- This will crash MATLAB
And,
mxSetField(currentTree,0,"class",classArray);
mxSetField(currentTree,0,"distrib",distribArray);
mxSetField(currentTree,0,"votes",votesCell);
mxSetField(currentTree,0,"codebase",codebaseCell);
mxSetCell(plhs[0],t,currentTree);
mxDestroyArray(classArray); <-- This will crash MATLAB
mxDestroyArray(distribArray); <-- This will crash MATLAB
mxDestroyArray(votesCell); <-- This will crash MATLAB
mxDestroyArray(codebaseCell); <-- This will crash MATLAB
mxDestroyArray(currentTree); <-- This will crash MATLAB
Once you clear up all of this mxDestroyArray crashing stuff, then we can get back to your original problem of a memory leak.
4 Comments
Azhar Sultan
on 12 Mar 2016
Azhar Sultan
on 12 Mar 2016
James Tursa
on 12 Mar 2016
Can you re-post your current code?
Azhar Sultan
on 12 Mar 2016
Categories
Find more on Generating Code in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!