PDA

View Full Version : Pixmap memory consumption



bunjee
29th November 2007, 12:53
Hey there, I'm developping a Qt app.

At some point in my application I'm loading 500 widgets and 1000 pixmap inside of it.

Since some pictures appears 2+ times, I've created a Pixmap "pool" manager to load once and for all a given Pixmap.


Here are the figures, compiled in static release :

at the beginning : my app takes 10 000 K of memory.
when 1000 Pixmap + Widgets loaded : my app takes 32 000 K of memory.
when unloaded : my app STILL takes 32 000 K of memory (if my Vista control panel is right).


I'm pretty sure I've deleted everything.

I'm not sure what could eat up so much memory since my "Pixmap manager" claims to contain 10 pixmap at the end.

wysota
29th November 2007, 13:24
Hard to say without seeing actual code. Did you explicitely call delete on every widget and pixmap? Or what do you mean by "being sure" they got deleted?

bunjee
29th November 2007, 14:40
Here is my getPixmap function


//================================================== ===========================
//================================================== ===========================

QPixmap & ZePixmapManager::getPixmap(QString & pixmapName,
const QPixmap & pixmap,
int width,
int height)
{
ZeLog::get()->Print("ZePixmapManager - getPixmap 2 %s %d %d\n",
pixmapName.toStdString().c_str(), width, height);

QPixmap tempPixmap(pixmap);

if (tempPixmap.isNull())
{
tempPixmap = QPixmap(PICTURE_DEFAULT);
pixmapName = PICTURE_DEFAULT;
}

for (unsigned int i = 0; i < mPixmapItem.size(); i++)
{
if (mPixmapItem[i]->getPixmapName() == pixmapName
&&
mPixmapItem[i]->width() == width
&&
mPixmapItem[i]->height() == height)
{
ZeLog::get()->Print("ZePixmapManager - Pixmap already exists\n");

mPixmapItem[i]->addInstance();

return mPixmapItem[i]->getPixmap();
}
}

ZePixmapItem * pixmapItem = new ZePixmapItem(pixmapName,
tempPixmap.
scaled(width, height,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));

mPixmapItem.push_back(pixmapItem);

ZeLog::get()->Print("ZePixmapManager - getPixmap %d %d\n",
pixmapItem->getPixmap().width(),
pixmapItem->getPixmap().height());

return pixmapItem->getPixmap();
}

and my delete pixmap :


//================================================== ===========================
//================================================== ===========================

bool ZePixmapManager::DeletePixmap(const QString & pixmapName,
const QPixmap & pixmap)
{
ZeLog::get()->Print("ZePixmapManager - DeletePixmap %d %s %d %d\n",
mPixmapItem.size(),
pixmapName.toStdString().c_str(),
pixmap.width(),
pixmap.height());

for (unsigned int i = 0; i < mPixmapItem.size(); i++)
{
if (mPixmapItem[i]->getPixmapName() == pixmapName
&&
mPixmapItem[i]->width() == pixmap.width()
&&
mPixmapItem[i]->height() == pixmap.height())
{
ZeLog::get()->Print("ZePixmapManager - DeletePixmap instance %d\n",
mPixmapItem[i]->getInstance());

mPixmapItem[i]->deleteInstance();
if (mPixmapItem[i]->getInstance() == 0)
{
ZeLog::get()->Print("ZePixmapManager - DeletePixmap complete\n");

delete mPixmapItem[i];
mPixmapItem.remove(i);
}

return true;
}
}

return false;
}

And here is my pixmap item :


//================================================== ===========================
//================================================== ===========================
// ZePixmapItem
//================================================== ===========================
//================================================== ===========================

ZePixmapItem::ZePixmapItem(const QString & pixmapName,
const QPixmap & pixmap) :
mPixmapName(pixmapName),
mPixmap(pixmap)
{
mWidth = mPixmap.width();
mHeight = mPixmap.height();

mInstance = 0;
addInstance();
}

//================================================== ===========================
//================================================== ===========================
ZePixmapItem::~ZePixmapItem()
{
}

//================================================== ===========================
//================================================== ===========================

void ZePixmapItem::addInstance()
{
mInstance++;
}

//================================================== ===========================
//================================================== ===========================

void ZePixmapItem::deleteInstance()
{
mInstance--;
}

jacek
29th November 2007, 15:07
for (unsigned int i = 0; i < mPixmapItem.size(); i++)
{
...
mPixmapItem.remove(i);
...
}
When you remove item from the list, all items after it are shifted from position n+1 to n, but you always increment i. Which means that every time you remove something, you also skip the next item.

wysota
29th November 2007, 15:22
What about deleting widgets? We haven't seen any widget related code.

bunjee
29th November 2007, 15:23
To jacek:


if (mPixmapItem[i]->getPixmapName() == pixmapName
&&
mPixmapItem[i]->width() == pixmap.width()
&&
mPixmapItem[i]->height() == pixmap.height())
{
ZeLog::get()->Print("ZePixmapManager - DeletePixmap instance %d\n",
mPixmapItem[i]->getInstance());

mPixmapItem[i]->deleteInstance();
if (mPixmapItem[i]->getInstance() == 0)
{
ZeLog::get()->Print("ZePixmapManager - DeletePixmap complete\n");

delete mPixmapItem[i];
mPixmapItem.remove(i);
}

return true;
}

I see what you mean, even though I'm not sure that's an issue since I'm returning true right after deleting an item, so the rest of the list is never checked.

bunjee
29th November 2007, 15:27
What about deleting widgets? We haven't seen any widget related code.

Actually I'm using a settable widget class of my own and I can certify its dtor is called :



//================================================== ===========================
//================================================== ===========================

ZeSettableLayout::ZeSettableLayout(QWidget * parent) :
QWidget(parent),
mLayout(this)
{
mSettableLayout = 0;
mWidget = 0;

getLayout().setMargin(0);
getLayout().setSpacing(0);

mOldParent = NULL;
}

//================================================== ===========================
//================================================== ===========================

ZeSettableLayout::~ZeSettableLayout()
{
Clear();
}

//================================================== ===========================
//================================================== ===========================

void ZeSettableLayout::setLayout(QLayout & settableLayout,
int stretch)
{
Clear();

mSettableLayout = &settableLayout;

getLayout().addLayout(mSettableLayout, stretch);
}

//================================================== ===========================
//================================================== ===========================

void ZeSettableLayout::setWidget(QWidget & widget,
int stretch,
Qt::Alignment alignment)
{
Clear();

mWidget = &widget;

// Saving old parent to restor it at deletion
mOldParent = getWidget().parentWidget();

getLayout().addWidget(mWidget, stretch, alignment);
getWidget().show();
}

//================================================== ===========================
//================================================== ===========================

void ZeSettableLayout::Clear()
{
if (mSettableLayout)
{
getLayout().removeItem(mSettableLayout);

mSettableLayout = NULL;
}

if (mWidget)
{
getLayout().removeWidget(mWidget);

// Retoring old parent for deletion
getWidget().setParent(mOldParent);
mOldParent = NULL;

//getWidget().hide();
mWidget = NULL;
}

update();
}


I have to reset Widget's parent everytime I set another one, otherwise its still parented to my settable layout class.

Maybe doing so prevent QT from freeing anything ? even when calling delete?

wysota
29th November 2007, 15:36
But do you call delete anywhere?

bunjee
29th November 2007, 15:45
to wysota,

Yes here :


//================================================== ===========================
//================================================== ===========================

void ZeServiceContactList::clearContact()
{
ZeLog::get()->Print("ZeServiceContactList - Clearing contacts\n");

for (unsigned int i = 0; i < mContactVector.size(); i++)
{
mOfflineExpand.RemoveWidget(*(mContactVector[i]));
emit removeWidget(*(mContactVector[i]));

ZeQuickViewController::get()->getDynamicInterface().
deleteMatch(mContactVector[i]->getStatusBubble());

ZeQuickViewController::get()->getDynamicInterface().
deleteMatch(mContactVector[i]->getPictureWidget());

// Deleting widgets...

delete mContactVector[i];
delete mContactPopVector[i];
delete mContactPictureVector[i];

// Deleting widgets...
}
mContactVector.clear();
mContactPopVector.clear();
mContactPictureVector.clear();
}

wysota
29th November 2007, 16:35
The problem could be completely elsewhere. Actually, not a problem. If Vista has a good memory allocator, it won't deallocate freed memory in case the application wants it back later. You could try running another application that is memory exhaustive and see if the amount of memory allocated for the first app starts decreasing.