mfc >> GDI resource leak

by Torsten Curdt » Fri, 28 Nov 2003 17:26:10 GMT

...taking over from another thread but with a
better subject line...


Why is this a resource leak?


void AbstractDialog::DrawBitmap( CDC* pDc, int pX, int pY, CBitmap*
pBitmap )
{
CDC memDC;
memDC.CreateCompatibleDC(pDc);

CBitmap* pOld = memDC.SelectObject(pBitmap);

BITMAP bm;
pBitmap->GetObject(sizeof(bm), &bm);
CSize size = pBitmap->SetBitmapDimension(bm.bmWidth, bm.bmHeight);

pDc->BitBlt(pX, pY, bm.bmWidth, bm.bmHeight, &memDC, 0, 0, SRCCOPY);

pDc->SelectObject(pOld);
}


Any idea?


mfc >> GDI resource leak

by Johan Rosengren » Fri, 28 Nov 2003 18:42:28 GMT


Torsten,

You must unselect pBitmap from memDC, not pDC.

Johan Rosengren
Abstrakt Mekanik AB

"Torsten Curdt" < XXXX@XXXXX.COM > a rit dans le message de






mfc >> GDI resource leak

by Torsten Curdt » Fri, 28 Nov 2003 20:00:37 GMT





*slap on the forehead* ...that was a stupid one!
Unfortunately I still see CreateCompatibleDC calls
without a DeleteDC :-(

void AbstractDialog::DrawBitmap( CDC* pDc, int pX, int pY, CBitmap*
pBitmap )
{
CDC memDC;
//memDC.CreateCompatibleDC(pDc);
}

As soon as I uncomment the CreateCompatibleDC call I seem to get
a resource leak. I also tried:

void AbstractDialog::DrawBitmap( CDC* pDc, int pX, int pY, CBitmap*
pBitmap )
{
CDC memDC;
memDC.CreateCompatibleDC(pDc);
memDC.DeleteObject();
}

but that did not help either! I am a bit stumped and don't understand
this! BTW: I call DrawBitmap like this:

void AbstractDialog::OnPaint()
{
CPaintDC dc(this);
OnDraw(dc);
}

void MyDialog::OnDraw( CPaintDC& dc )
{
DrawBitmap(&dc,...);
}

Any idea?


GDI resource leak

by Johan Rosengren » Sat, 29 Nov 2003 16:31:33 GMT

Torsten,

"Torsten Curdt" < XXXX@XXXXX.COM > a rit dans le message de


<snip>

<snip>

To go back to the original code, it should look something like this:

void AbstractDialog::DrawBitmap( CDC* pDc, int pX, int pY, CBitmap*
pBitmap )
{
CDC memDC;
memDC.CreateCompatibleDC(pDc);

CBitmap* pOld = memDC.SelectObject(pBitmap);

BITMAP bm;
pBitmap->GetObject(sizeof(bm), &bm);
CSize size = pBitmap->SetBitmapDimension(bm.bmWidth, bm.bmHeight);

pDc->BitBlt(pX, pY, bm.bmWidth, bm.bmHeight, &memDC, 0, 0, SRCCOPY);

memDC.SelectObject(pOld); // Unselecting pBitmap from the mem CDC

}

This should be enough to avoid GDI leaks, but I, being old and conservative,
would also add a memDC.DeleteDC - if only for clarity :-)))

Johan Rosengren
Abstrakt Mekanik AB





Similar Threads

1. MFC GDI Resource leak reintroduced in WinXP SP2?

2. tool to find GDI resource leak

3. Does OnCtlColor create GDI resource leak?

I was chasing after some memory leaks and found something unexpected.
It appears that changing the default brush in OnCtlColor by returning
hbr=CreateSolidBrush(color); generates GDI resource leak. Anyone can
comment?

Cheers,
Henryk Birecki


4. Preventing memory and resource leaks with GDI Objects ???

5. Disposal of GDI Resources and GDI Limits, a puzzling question (for me at least)

When working with GDI+, calling the CreateGraphics method to draw on a
control has normally been frowned upon and it is always emphasized to
dispose of pens and brushes and other GDI objects lest you run out.

But consider the following code (in a timer elapsed event on a Windows
Form):

private void TimerFunc(object sender, System.Timers.ElapsedEventArgs
e) {
    Graphics gdi  = this.CreateGraphics();

    int x, y;
    int w, h;
    int r, g, b;

    x = _random.Next(0, this.ClientRectangle.Width + 1);
    y = _random.Next(0, this.ClientRectangle.Height + 1);
    w = _random.Next(5, 250);
    h = _random.Next(5, 250);
    r = _random.Next(0, 256);
    g = _random.Next(0, 256);
    b = _random.Next(0, 256);

    Pen p  = new Pen(Color.FromArgb(255, r, g, b));

    gdi.DrawEllipse(p, x, y, w, h);
}

Note that I am calling CreateGraphics and creating a new Pen without
disposing of either.  This method handles a Timer Elapsed event.  I
set the interval of the timer to 50ms.  So basically, i draw random
ellipses on the form.

But when I montior the app in Task Manager, Process explorer, or a GDI
monitor, the number of GDI objects does not change.  They do not go
up, even if I let the code run for minutes at a time.  I even added
the following loop in the elapsed event:

List<Pen> penList = new List<Pen>(50000)
for (int i = 0;i <= 50000;i++) {
   penList.Add(new Pen(Color.FromArgb(255, r, g, b));
}

Even after creating 50000 new Pens, the GDI object count did not
change!  Memory usage increased (Working Set size) slightly but not in
significant amounts for the duration of this test.

Can anyone explain this behavior?  I expected to see the GDI object
count increase since I did not dispose of any of the objects.  My
understanding was that the gc only triggered on memory pressure and
not handle pressure.

Why bother disposing of pens and brushes and the like if it doesn't
seem to have an effect on the GDI handle count?  Have I missed
something obvious?

Thanks for any insight!

Chris

6. TreeView checkbox gdi memory leak - CSharp/C#

7. GDI objects leak

I have two distinct .NET component having a UI containg a datagridView 
with some icons in some cells.
The two components, that are very similar, are loaded by a COM application.
The COM application is very expensive in term of GDI object handler. 
They are in some cases 8000.

Launching the first plugin the GDI objects loaded become 8002 and 
closing the plugin they return 8000.

Launching the second plugin the GDI objects explode to 12000 and closing 
the plugin they remain 11500.

So, as the limit set in registry is 15000, after some time the tool crashes.

Note that launching the .NET components without the COM components I can 
note that the second plugin gets only 40 GDI objects handles but it 
doesn' dispose all them on closing.

I try to invoke the Dispose method of the form, the double buffering....
but the result is the same.
Someone says it is a problem related with XP SP2.

Have someone any idea about that problem?

8. Need Help Fixing GDI Leaks