Reputation: 291
Alright; so I'm finding an odd memory leak when attempting to use cvCreateMat to make room for my soon-to-be-filled mat. Below is what I am attempting to do; adaptiveThreshold didn't like it when I put the 3-channel image in, so I wanted to split it into its separate channels. It works! But every time we go through this particular function we gain another ~3MB of memory. Since this function is expected to run a few hundred times, this becomes a rather noticeable problem.
So here's the code:
void adaptiveColorThreshold(Mat *inputShot, int adaptiveMethod, int blockSize, int cSubtraction)
{
Mat newInputShot = (*inputShot).clone();
Mat inputBlue = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);
Mat inputGreen = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);
Mat inputRed = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);
for(int rows = 0; rows < newInputShot.rows; rows++)
{
for(int cols = 0; cols < newInputShot.cols; cols++)
{
inputBlue.data[inputBlue.step[0]*rows + inputBlue.step[1]*cols] = newInputShot.data[newInputShot.step[0]*rows + newInputShot.step[1]*cols + 0];
inputGreen.data[inputGreen.step[0]*rows + inputGreen.step[1]*cols] = newInputShot.data[newInputShot.step[0]*rows + newInputShot.step[1]*cols + 1];
inputRed.data[inputRed.step[0]*rows + inputRed.step[1]*cols] = newInputShot.data[newInputShot.step[0]*rows + newInputShot.step[1]*cols + 2];
}
}
adaptiveThreshold(inputBlue, inputBlue, 255, adaptiveMethod, THRESH_BINARY, blockSize, cSubtraction);
adaptiveThreshold(inputGreen, inputGreen, 255, adaptiveMethod, THRESH_BINARY, blockSize, cSubtraction);
adaptiveThreshold(inputRed, inputRed, 255, adaptiveMethod, THRESH_BINARY, blockSize, cSubtraction);
for(int rows = 0; rows < (*inputShot).rows; rows++)
{
for(int cols = 0; cols < (*inputShot).cols; cols++)
{
(*inputShot).data[(*inputShot).step[0]*rows + (*inputShot).step[1]*cols + 0] = inputBlue.data[inputBlue.step[0]*rows + inputBlue.step[1]*cols];
(*inputShot).data[(*inputShot).step[0]*rows + (*inputShot).step[1]*cols + 1] = inputGreen.data[inputGreen.step[0]*rows + inputGreen.step[1]*cols];
(*inputShot).data[(*inputShot).step[0]*rows + (*inputShot).step[1]*cols + 2] = inputRed.data[inputRed.step[0]*rows + inputRed.step[1]*cols];
}
}
inputBlue.release();
inputGreen.release();
inputRed.release();
newInputShot.release();
return;
}
So going through it one line at a time...
So far, so good - need memory to hold the data. newInputShot gets its data right off the bat, but inputRGB need to get their data from newInputShot - so we just allocate the space to be filled in the upcoming for-loop, which (as expected) allocates no new memory, just fills in the space already claimed.
The adaptiveThresholds don't add any new memory either, since they're simply supposed to overwrite what is already there, and the next for-loop writes straight to inputShot; no new memory needed there. So now we get around to (manually) releasing the memory.
Now, according to the OpenCV documentation site: "OpenCV handles all the memory automatically."
First of all, std::vector, Mat, and other data structures used by the functions and methods have destructors that deallocate the underlying memory buffers when needed. This means that the destructors do not always deallocate the buffers as in case of Mat. They take into account possible data sharing. A destructor decrements the reference counter associated with the matrix data buffer. The buffer is deallocated if and only if the reference counter reaches zero, that is, when no other structures refer to the same buffer. Similarly, when a Mat instance is copied, no actual data is really copied. Instead, the reference counter is incremented to memorize that there is another owner of the same data. There is also the Mat::clone method that creates a full copy of the matrix data.
TLDR the quote: Related mats get clumped together in a super-mat that gets released all at once when nothing is left using it.
This is why I created newInputShot as a clone (that doesn't get clumped with inputShot) - so I could see if this was occurring with the inputRGBs. Well... nope! the inputRGBs are their own beast that refuse to be deallocated. I know it isn't any of the intermediate functions because this snippet does the exact same thing:
void adaptiveColorThreshold(Mat *inputShot, int adaptiveMethod, int blockSize, int cSubtraction)
{
Mat newInputShot = (*inputShot).clone();
Mat inputBlue = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);
Mat inputGreen = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);
Mat inputRed = cvCreateMat(newInputShot.rows, newInputShot.cols, CV_8UC1);
inputBlue.release();
inputGreen.release();
inputRed.release();
newInputShot.release();
return;
}
That's about as simple as it gets. Allocate - fail to Deallocate. So what's going on with cvCreateMat?
Upvotes: 0
Views: 1313
Reputation: 215
I would suggest not to use cvCreateMat and you don't need to clone the original Mat either. Look into using split() and merge() functions. They will do the dirty work for you and will return Mat's that will handle memory for you. I don't have OpenCV installed right now so i can't test any of the code but i'm sure that's the route you want to take.
Upvotes: 1