locked
GDI (graphics) Disposing objects properly RRS feed

  • Question

  • Ok, I just got a shock that GDI objects (for me, Pens, Brushes, DCs (Canvasses), Fonts, and Regions) are NOT garbage collected like everything else in .NET.  We must dispose of them ourselves.

    That said, I have a few questions about what items need to be disposed.

    Brushes from System Brushes (or pens or fonts)

    If I say

    Brush textBrush = new Brush(...);

    ...we know I have to dispose that.  But if I said...

    Brush textBrush = System.Drawing.Brushes.Black;

    ...do I need to dispose that?  I wasn't sure because I never called new()

    SubComponents of Graphics

    When I create a region like this...

    Graphics g...

    g.Clip = new Region(new Rectangle(rect.Left - 50, rect.Top, 100, bh));

    ...do I need to do a

    g.Clip.Dispose();

    ...or will the g.Dispose() take care of that?


    I'd rather live with false hope than with false despair.

    Friday, June 10, 2016 5:13 PM

Answers

  • Hi,

    I was thinking about that a lot, too. I fear that it is not that easy.

    a) One easy example is the property, that is IDisposable. We can just take this:

    public Brush SomeBrush { get; set; }

    We cannot know if this is a standard brush or not. So of course we have to dispose it and when implementing such constants we have to take care of this szenario. So the standard brushes will be disosed and they should be implemented in a way that this is possible without strange results.

    b) Getting IDisposable objects as result from a function: These will be disposed! There is almost no discussion about this. Even with c++ it i done this way. A function returns a pointer to memory or a handle and you have to take care of that because it is seen as requested. "Ownership" is transfered.

    c) Handing elements over as parameters - these are not disposed. These are never owned by you - you just got them for a short period of time.

    And that is exactly how the code analysis works:
    If you have a IDisposable Property / field, then you get a warning if you do not dispose it.
    If you introduce a local variable that is IDisposable, then you get a warning if you do not dispose it.
    Such warning will not come on IDisposable method arguments.

    But all this is really a question of design. The thoughts are all valid and I do not say, that it is wrong. That are also legal patterns. I just try to use the code analysis as much as possible and design everything in that way.

    But there are also special cases. Streams are special cases. You can create a stream on top of another stream. When closing the outer stream, the inner stream is also closed. So when you have something like:
    Stream stream1 = new WhateverStream();
    Stream stream2 = new SomeOtherStream(stream1);
    then there will be a warning if you Dispose both instances. stream1 will probably be disposed 2 times.

    So yes, it is really complex and you have to think carefully about it. But the core pattern should always be (in my eyes) to dispose elements and design everything in that way:
    - So my Dispose Method only disposes if it wasn't disposed.
    - When this might be a probem (e.g. SqlConnection), then build up "layers". SqlConnection has a pooling inside. oSo there are some kind of layers. You have an internal connection. This is handled internally. The developer gets a connection instance that he can (and shoudld) dispose whenever he is done. So he simply does not need to work long time with a SqlConnection including all the crap statechecking and so on.

    Just as some thoughts from my side. I hope that this didn't confuse and was useful. It is complex and there is sometimes no "correct" and "wrong". The worst case is, that an element is not disposed and then some resources are in use till the GC finalizes the instance.

    With kind regards,

    Konrad

    • Proposed as answer by DotNet Wang Sunday, June 19, 2016 5:35 AM
    • Marked as answer by DotNet Wang Monday, June 20, 2016 9:00 AM
    Monday, June 13, 2016 8:12 PM

All replies

  • ...we know I have to dispose that.  But if I said...

    Brush textBrush = System.Drawing.Brushes.Black;

    ...do I need to dispose that?  I wasn't sure because I never called new()

    It's not an object out the gate,  and if you try to address it, it's probably going to blow up the program with an 'object not set to an instance of an object'.  

    It follows the basic principles of OO, and it doesn't matter if it is Java or .NET, which are both Object Oriented Programming language platforms.

     https://alfredjava.wordpress.com/2008/07/08/class-vs-object-vs-instance/

    g.dispose(); //should do it. I guess you could also just set g to a null value and GC would roll around and get it.

    Friday, June 10, 2016 8:30 PM
  • Actually the textBrush works just fine, and it doesn't croak when you try to dispose it either.

    As for OO principals, I am aware, it's just that C#.NET is so insulated from the details sometimes, it's hard to be sure when you are making objects or pointers.  This is especially true since they tell us not to dispose our objects, we should just let the framework take care of it.


    I'd rather live with false hope than with false despair.

    Saturday, June 11, 2016 2:24 AM
  • Hi,

    just one important point:

    Dispose is not releasing any memory. In a managed environment, you do not release the memory. That is done by the Garbage Collector. 

    The problem with .Net is simply, that it also has unmanaged stuff. And when resources are used you might want to close them at a specific time (e.g. to open it again). That is where Dispose comes to its use. So it might release some unmanaged memory but no managed memory is freed at a dispose call.

    Also important: you do not have pointers in managed c#. With the platform invoke you can get native pointers and handles but even these are not of direct use. You can only use it in other invokes or you can marshal them to c# types/references.

    With kind regards,

    Konrad

    Saturday, June 11, 2016 6:03 AM
  • With regard to the built-in brushes, I would think that you should not dispose them, because you didn't actually create them.

    To build on what Konrad said a bit, in .NET you don't know when your object will be cleaned up by the garbage collector.  But for some non-managed resources, you want to release those as soon as possible. 

    A typical example is database connections, since you can only have so many.  You want to close them as soon as possible.

    So if your object opened a database connection, it should implement IDispose and close the connection on Dispose.

    But if someone passed an object to you that contains a database connection, you shouldn't Dispose it because someone else might be using that connection - since you didn't create that object.  I think that would be a good rule of thumb: don't Dispose objects that you don't own.

    For your other question, as far as I can tell, you aren't responsible for walking the object graph and calling Dispose on each object; I think it's up to each object to dispose it's components.  There's no way that this could be enforced otherwise; what if the object had a private member variable that implemented IDispose?  Without resorting to reflection, you could never Dispose it.

    Phil

    Monday, June 13, 2016 7:42 PM
  • Hi,

    I was thinking about that a lot, too. I fear that it is not that easy.

    a) One easy example is the property, that is IDisposable. We can just take this:

    public Brush SomeBrush { get; set; }

    We cannot know if this is a standard brush or not. So of course we have to dispose it and when implementing such constants we have to take care of this szenario. So the standard brushes will be disosed and they should be implemented in a way that this is possible without strange results.

    b) Getting IDisposable objects as result from a function: These will be disposed! There is almost no discussion about this. Even with c++ it i done this way. A function returns a pointer to memory or a handle and you have to take care of that because it is seen as requested. "Ownership" is transfered.

    c) Handing elements over as parameters - these are not disposed. These are never owned by you - you just got them for a short period of time.

    And that is exactly how the code analysis works:
    If you have a IDisposable Property / field, then you get a warning if you do not dispose it.
    If you introduce a local variable that is IDisposable, then you get a warning if you do not dispose it.
    Such warning will not come on IDisposable method arguments.

    But all this is really a question of design. The thoughts are all valid and I do not say, that it is wrong. That are also legal patterns. I just try to use the code analysis as much as possible and design everything in that way.

    But there are also special cases. Streams are special cases. You can create a stream on top of another stream. When closing the outer stream, the inner stream is also closed. So when you have something like:
    Stream stream1 = new WhateverStream();
    Stream stream2 = new SomeOtherStream(stream1);
    then there will be a warning if you Dispose both instances. stream1 will probably be disposed 2 times.

    So yes, it is really complex and you have to think carefully about it. But the core pattern should always be (in my eyes) to dispose elements and design everything in that way:
    - So my Dispose Method only disposes if it wasn't disposed.
    - When this might be a probem (e.g. SqlConnection), then build up "layers". SqlConnection has a pooling inside. oSo there are some kind of layers. You have an internal connection. This is handled internally. The developer gets a connection instance that he can (and shoudld) dispose whenever he is done. So he simply does not need to work long time with a SqlConnection including all the crap statechecking and so on.

    Just as some thoughts from my side. I hope that this didn't confuse and was useful. It is complex and there is sometimes no "correct" and "wrong". The worst case is, that an element is not disposed and then some resources are in use till the GC finalizes the instance.

    With kind regards,

    Konrad

    • Proposed as answer by DotNet Wang Sunday, June 19, 2016 5:35 AM
    • Marked as answer by DotNet Wang Monday, June 20, 2016 9:00 AM
    Monday, June 13, 2016 8:12 PM