Reputation: 173
I've inherited a substantial Qt5 project, where the accumulative memory leakage is becoming a serious issue. (Yes, memory leakage should rarely be tolerated but with real life budget and time constraints...).
This GUI reads image data into objects of a voxel class, to be displayed graphically. The data comes either from file or buffer (if acquired live) and is stored as a nest qvector, ie:
QVector < QVector <Voxel *> > cVoxel;
When an image is read from file, cVoxel
is initialized using QVector.resize(0)
.
cVoxel.resize(0);
When an image save to file is opened, a local Voxel
pointer is created and pushed to the end of cVoxel
, once for every pixel so looping over all rows and columns:
for (iRow = 0; iRow < nRows; ++iRow)
{
for (iCol = 0; iCol < nCols; ++iCol)
{
Voxel *v = new Voxel;
cVoxel[iRow].push_back(v);
// Code for reading data into cVoxel removed here
...
}
}
Courtesy of the useful comments below, I've now had some success in seeing memory usage decrease in the Windows Task Manager, by nesting destruction of the cVoxel QVector in my CTOR. Along the lines of:
for (iRow = 0; iRow < nRows; iRow++)
{
for (iCol = 0; iCol < nCols; iCol++)
{
delete cVoxel[iRow][iCol];
}
}
Ideally, a major rewrite is the best solution. But in the real world, I'll have to try and fix the bigger leaks and hope that's enough until there's enough resources available for a more ideal solution.
Voxel
itself, but there's nothing obvious there.cVoxel
is successfully released? If I keep opening and shut images, the app's memory consumption keeps increasing in similar step. It never decreases after closing any/all opened images.cVoxel
. I have tried a few approaches (and read to learn more), but so far litte luck. ----EDIT ----
Apologies for the messy ad-hod commenting below, but this is certainly helping me reduce the memory leakages (complete stoppage will hopefully happen in due course..).
I've edited in-line above to (hopefully) make this post clearer, and removed my best case effort as it had no impact on the memory leak. The significant alteration above are the (2) brief paragraphs in italics.
I also need to investigate @richardcitter (sp?) polymorphism related suggestion.
--- EDIT3 ---
Removed Edit2, posted that (new) question separately here.
Also, I'm pretty confident the answer below should fix this question - I just need to figure out how to use qvector.resize()
or find a workaround to it.
Upvotes: 0
Views: 437
Reputation: 173
@SomeProgrammerDude: You got me 9/10 towards the solution.
As outlined in a connected SO post, I decided against smart pointers in the end. The above solution introduced (for me) the issue of the compiler trying to reference a deleted function. Otherwise it is correct with a couple of modifications:
QVector < QVector <Voxel *> > cVoxel;
Initialisation:
cVoxel.resize(0);
Memory assignment:
{
for (int i = 0; i < rows; ++i)
{
cVoxel.push_back( QVector <Voxel *> () );
for (int j = 0 ; j < cols ; ++j)
{
Voxel *v = new Voxel;
cVoxel[i].push_back(v);
}
}
}
Finally DTOR releasing the memory:
int iRow, iCol;
for (iRow = 0; iRow < rows; iRow++)
{
for (iCol = 0; iCol < cols; iCol++)
{
delete cVoxel[iRow][iCol];
}
}
Upvotes: 0
Reputation: 409442
To solve the undefined behavior and to properly make sure that you don't need to make any extra allocations, you can preallocate the number of elements in the vectors. You already do this when you call resize(0)
, but instead of setting the size you really need, you make the size zero, you make the vector empty.
I would suggest something like this instead:
First use std::unique_ptr
as suggested by Richard Critten:
QVector < QVector < std::unique_ptr <Voxel> > > cVoxel;
If Qt have its own unique pointer type you could use that instead.
Then when you create the you use resize
to set the actual size of the vectors:
cVoxel.resize(nRows);
Then you can use plain indexes into the vector. Set the size for the inner vectors as well:
for (iRow = 0; iRow < nRows; ++iRow)
{
cVoxel[iRow].resize(nCols); // Resize to the number of columns
for (iCol = 0; iCol < nCols; ++iCol)
{
cVoxel[iRow][iCol].reset(new Voxel); // Create the actual Voxel object
// Code for reading data into cVoxel here
...
}
}
Since you use std::unique_ptr
(or the Qt equivalent) the memory managed by the std::unique_ptr
object will be automatically free'd once the object is destructed. So no more memory leaks, when the cVoxel
vector goes out of scope or is otherwise destructed, so will your Voxel
objects be.
Upvotes: 1