Dispose

  • Thread starter Thread starter Hilton
  • Start date Start date
H

Hilton

Hi,

Using the standard CF 1.x System.* libraries, which objects do we
specifically need to Dispose() after doing a "new"? Or more generically, as
C# engineers, we tend to leave memory management to the GC. However, when
do we have to be explicit about things and which object require this?

For short-term objects such as File Streams etc, I use "using (FileStream fs
= ...)"

Thanks,

Hilton
 
Follow the rule of thumb: If an object has a Dispose method, call it when
you are done with the object. (the using statement does the same).

Cheers
Daniel
 
Sure, but you wouldn't dispose a Button - right? If so, then VS generates
leaky code, cause it doesn't.

Hilton
 
Sure, but you wouldn't dispose a Button - right?

I would, it has windows handles. I was creating usercontrols quite a lot
and adding/removing them from my form (wizard interface) and it leaked a lot
until I disposed of the usercontrol.
If so, then VS generates leaky code, cause it doesn't.

In your form's code it doesn't, but it probably does within the Form class.
 
When a Form is closed it calls Dispose on all contained Forms, so you use
that knowledge to not dispose them, but generally speaking the designer
writes the code to create those anyway. So let's alter Daniel's general
rule slightly:

If you write code to create an objetct that exposes a Dispose method, then
you should also write code to call Dispose on said object when it's no
longer being used.

-Chris
 
Thanks Chris. I think it is easy to get lulled into a false sense of
security; i.e. the GC will clean up my objects.

Let's take an example: why should I have to Dispose of a Bitmap? I
understand the internals (pixels are create in C world), but does this mean
that I now have to do all this memory management because Microsoft 'hacked'
up their classes? For example, why doesn't the Bitmap class just look like:

class Bitmap
{
int width;
int height;
...other stuff...
bytes[] pixels
}

Then when the GC nukes this Bitmap object, the bytes[] go with it and I
don't have to do anything. Sure, I can still call Dispose to clean up
quicker, but I am no longer *forced* to clean up the pixels as I am now.

Maybe it's just me, but I think this is exceptionally bad. Heck, to make
matters worse, while I still have to do mallocs and frees on my bitmaps
(i.e. new and Dispose), I cannot even access those pixels to do some image
processing (no LockBits in pre-CF 2.0). It's the worse of both worlds.

OK, while I'm ranting, why the heck is Bitmap part of System.Drawing? Does
this mean I cannot write a command line image processing EXE?

I'm sure I've got somethings wrong and I don't understand some things, so
please correct me as necessary.

Thanks,

Hilton
 
Let's take an example: why should I have to Dispose of a Bitmap? I
understand the internals (pixels are create in C world), but does this
mean that I now have to do all this memory management because Microsoft
'hacked' up their classes? For example, why doesn't the Bitmap class just
look like:

class Bitmap
{
int width;
int height;
...other stuff...
bytes[] pixels
}

Because the managed bitmap wraps a native bitmap. It therefore contains
references to unmanaged memory, which get released in its finalizer.
Calling Dispose lets the object free it's internally held native objects
without having to wait for a collection.
Then when the GC nukes this Bitmap object, the bytes[] go with it and I
don't have to do anything. Sure, I can still call Dispose to clean up
quicker, but I am no longer *forced* to clean up the pixels as I am now.

But if it had your representation, then it would have to do a conversion to
a native bitmap every time your bitmap was sent to GDI (painful perf).
Maybe it's just me, but I think this is exceptionally bad. Heck, to make
matters worse, while I still have to do mallocs and frees on my bitmaps
(i.e. new and Dispose), I cannot even access those pixels to do some image
processing (no LockBits in pre-CF 2.0). It's the worse of both worlds.

The lack of LockBits was just a poor decision. You're still not doing a
malloc and free, as that would leave the potential for leaks and/or illegal
accesses. It's still managed, and if you don't call dispose, it doesn't
mean you'll have a leak, it just means the object will hold its unmanaged
allocations until it is collected. Calling Dispose manually simply allows
your application to free up large amounts of memory without the expense of a
GC. In fact, from both a perf and resource perspective, this is better than
if it didn't expose Dispose.
OK, while I'm ranting, why the heck is Bitmap part of System.Drawing?
Does this mean I cannot write a command line image processing EXE?

Because Bitmaps logically have to do with drawing. Where else would you
propose they be? A command line application is not relevent. You can
still use Bitmaps in a console app. You can create Forms in a Console app
too. The only thing a Console app does (actually it's an omission rather
than an addition) is to not start a message pump with a call to
Application.Run. You can still do that too if you want (though not without
a Form using just the CF - another poor decision).
I'm sure I've got somethings wrong and I don't understand some things, so
please correct me as necessary.

-Chris
 
It will look like that eventually, but for now it uses native implementation
so it can work with current OS based on native code. Since OS has no idea
what "managed" bitmap is, you won't be able to load, draw and store it using
OS services which makes "managed" bitmap unusable.



It's also possible to create a hydrogen powered car today, but it's not at
all useful as there are no hydrogen fuel stations not to mention there's no
good way to produce hydrogen.



That's why Bitmap uses native implementation and we're driving gas powered
cars.



--
Best regards,

Ilya

This posting is provided "AS IS" with no warranties, and confers no rights.

*** Want to find answers instantly? Here's how... ***

1. Go to
http://groups-beta.google.com/group/microsoft.public.dotnet.framework.compactframework?hl=en
2. Type your question in the text box near "Search this group" button.
3. Hit "Search this group" button.
4. Read answer(s).

Hilton said:
Thanks Chris. I think it is easy to get lulled into a false sense of
security; i.e. the GC will clean up my objects.

Let's take an example: why should I have to Dispose of a Bitmap? I
understand the internals (pixels are create in C world), but does this
mean that I now have to do all this memory management because Microsoft
'hacked' up their classes? For example, why doesn't the Bitmap class just
look like:

class Bitmap
{
int width;
int height;
...other stuff...
bytes[] pixels
}

Then when the GC nukes this Bitmap object, the bytes[] go with it and I
don't have to do anything. Sure, I can still call Dispose to clean up
quicker, but I am no longer *forced* to clean up the pixels as I am now.

Maybe it's just me, but I think this is exceptionally bad. Heck, to make
matters worse, while I still have to do mallocs and frees on my bitmaps
(i.e. new and Dispose), I cannot even access those pixels to do some image
processing (no LockBits in pre-CF 2.0). It's the worse of both worlds.

OK, while I'm ranting, why the heck is Bitmap part of System.Drawing?
Does this mean I cannot write a command line image processing EXE?

I'm sure I've got somethings wrong and I don't understand some things, so
please correct me as necessary.

Thanks,

Hilton



When a Form is closed it calls Dispose on all contained Forms, so you use
that knowledge to not dispose them, but generally speaking the designer
writes the code to create those anyway. So let's alter Daniel's general
rule slightly:

If you write code to create an objetct that exposes a Dispose method,
then you should also write code to call Dispose on said object when it's
no longer being used.

-Chris
 
Chris,
Let's take an example: why should I have to Dispose of a Bitmap? I
understand the internals (pixels are create in C world), but does this
mean that I now have to do all this memory management because Microsoft
'hacked' up their classes? For example, why doesn't the Bitmap class
just look like:

class Bitmap
{
int width;
int height;
...other stuff...
bytes[] pixels
}

Because the managed bitmap wraps a native bitmap. It therefore contains
references to unmanaged memory, which get released in its finalizer.
Calling Dispose lets the object free it's internally held native objects
without having to wait for a collection.
Correct.

Then when the GC nukes this Bitmap object, the bytes[] go with it and I
don't have to do anything. Sure, I can still call Dispose to clean up
quicker, but I am no longer *forced* to clean up the pixels as I am now.

But if it had your representation, then it would have to do a conversion
to a native bitmap every time your bitmap was sent to GDI (painful perf).

Right, that's my point. Because of the *internal* implementation, we have
to modify the way we write C# code, and get forced to take a step backwards
and essentially do our own memory management as the GC cannot do it for us.

The lack of LockBits was just a poor decision. You're still not doing a
malloc and free, as that would leave the potential for leaks and/or
illegal accesses.

It's still managed, and if you don't call dispose, it doesn't mean you'll
have a leak, it just means the object will hold its unmanaged allocations
until it is collected. Calling Dispose manually simply allows your
application to free up large amounts of memory without the expense of a
GC. In fact, from both a perf and resource perspective, this is better
than if it didn't expose Dispose.

Sorry Chris, I think you're wrong on this one. Having a this.bmp = new
Bitmap (1024, 1024) in a timer loop throws an OOM exception, not just a GC
call. Essentially the "new Bitmap()" does a malloc and the "Dispose ()"
does a free - so yes, your 100% responsible for memory management. To test:

Create a form, put "Timer timer; Bitmap bmp;" at the top, create the timer
object using:

this.timer = new Timer ();
this.timer.Interval = 500;
this.timer.Tick += new EventHandler(timer_Tick);
this.timer.Enabled = true;

Then add:

private void timer_Tick(object sender, EventArgs ea)
{
bool error = false;

this.timer.Enabled = false;

try
{
this.bmp = new Bitmap (1024, 1024);

this.Text = DateTime.Now.ToLongTimeString();
}
catch (Exception e)
{
error = true;

using (System.IO.StreamWriter sw = new
System.IO.StreamWriter ("exp.txt"))
{
sw.WriteLine (e.ToString());
}

this.Text = "Exception";
}
this.timer.Enabled = !error;
}

Hilton
 
Right, that's my point. Because of the *internal* implementation, we have
to modify the way we write C# code, and get forced to take a step
backwards and essentially do our own memory management as the GC cannot do
it for us.

So you propose rewriting the Win32 to convenience C#developers? I think
you're asking a bit much there.
Sorry Chris, I think you're wrong on this one. Having a this.bmp = new
Bitmap (1024, 1024) in a timer loop throws an OOM exception, not just a GC
call. Essentially the "new Bitmap()" does a malloc and the "Dispose ()"
does a free - so yes, your 100% responsible for memory management.

No you're not - you misunderstand the GC. You're running out of memory
because a GC is never getting called. Use RPM and you'll see that no
collection is taking place. That's why you run out of memory. Do the same
test and at some point before it normally would OOM send the app to the
background then go back to it - this forces a collection. It will last
longer.

So the question is "why is the GC not collecting when the OOM happens?"
It's because you have a large amount of unmanaged data that the GC can't
track, so it doesn't know it can be freed - because you didn't call Dispose.
In a perfect world it would all happen magically, but then maybe the code
would also write itself. In a less than perfect world, we have to
understand the limitations of a system and work within those bounds.

-Chris


-Chris
 
Back
Top