IDisposable

Hello folks,

If a class implements the IDisposable interface (and hence, has a Dispose method), is it my responsibility to call it all the time? In other words, if I dont call it, will there be resource leaks? For example this code:
[code]
void Test()
{
System.IO.FileStream fs = File.OpenRead("something.something");
}
[/code]
When fs gets out of scope and its Finalize called, will it "clean" itself up? Will GC sees this class has IDisposable and calls Dispose? Or should the finalize method of FileStream take care of that?

I'm asking this because I have a class that has some legacy Win32 resource. Right now I'm writing something like this:
[code]
class Test: IDisposable
{
private some_win32_resource;

public Test() { some_win32_resource = null; }

public virtual void Dispose()
{
if(some_win32_resource != null)
{
free_win32_resource(some_win32_resource);
some_win32_resource = null;
}

GC.SurplessFinalize(this);
}

~Test()
{
if(some_win32_resource != null)
{
free_win32_resource(some_win32_resource);
some_win32_resource = null;
}
}
}
[/code]
Is the logic in the code above correct? I ildasm'ed System.Drawing.Image and its using something like the above, but when I run FxCop (from gotdotnet.com) on it, I have a warning stating that I cannot call anything from my finalize but base members.

Thanks

Comments

  • I'm not 100% sure but i remember that C# is supposed to have GC, hence you shouldn't need to worry about such things. Then again, you "shouldn't" and "need not" are two different things, aren't they?

    I'm no deep-rooted C# expert but i believe that once all the references to an object are gone, it gets disposed by the GC automaticaly.



    Kind Regards
    Konrad
    ----------------------------
    (+46/0) 708-70 73 92
    [email protected]
    http://konrads.webbsida.com

  • By the way - why not test it? Create a large number instances and then remove the reference. Check the memory status and you'll see what happens.



    Kind Regards
    Konrad
    ----------------------------
    (+46/0) 708-70 73 92
    [email protected]
    http://konrads.webbsida.com

  • Well, I did, it does not leak. I seem to get the correct code going in the class sample I posted, if you call Dispose manually, memory is freed and the GC.SupressFinalize call make sure ~Test is not called, if I dont call Dispose, ~Test gets called when GC starts collecting (for example, if I call GC.Collect).

    All is good, I'm just wondering why FxCop doesnt like my class! Here's my new code:
    [code]
    using System;
    using System.Runtime.InteropServices;

    public class MyClass: MarshalByRefObject, IDisposable
    {
    IntPtr m_data;

    public MyClass()
    {
    m_data = IntPtr.Zero;
    }

    public void Allocate()
    {
    GC.KeepAlive(this);
    if(m_data != IntPtr.Zero)
    Marshal.FreeHGlobal(m_data);

    m_data = Marshal.AllocHGlobal(8096);
    }

    public virtual void Dispose()
    {
    GC.KeepAlive(this);
    if(m_data != IntPtr.Zero)
    {
    Marshal.FreeHGlobal(m_data);
    m_data = IntPtr.Zero;
    }

    GC.SuppressFinalize(this);
    }

    ~MyClass()
    {
    GC.KeepAlive(this);
    if(m_data != IntPtr.Zero)
    {
    Marshal.FreeHGlobal(m_data);
    m_data = IntPtr.Zero;
    }
    }
    }
    [/code]

    It's working fine, and there's no way to cause memory leak. However when I run FxCop on it, I get this warning:
    [italic]
    The Finalize method of 'ConsoleApplication4.MyClass' makes the following calls that are suspect:
    System.Runtime.InteropServices.Marshal.IsNotWin32Atom(IntPtr)
    System.Runtime.InteropServices.Marshal.FreeHGlobal(IntPtr)
    [/italic]
    And this explination:
    [italic]
    A Finalize method should not call methods other than those in its declaring type or its base type since these are the only objects that are guaranteed to be available (not yet finalized).
    [/italic]
    And more info:
    [italic]
    Finalizers are not guaranteed to run in any specific order, which means a finalizer that calls a type other than its own or its base type risks calling an object that has already been finalized. This can result in an exception or unpredictable behavior. In either case, the finalizer might leak unmanaged resources.
    [/italic]

    How on earth are you supposed to free resources in yoru finalize if you are not supposed to call any method expect base class members?

    Any help is greatly appreciated.

    : By the way - why not test it? Create a large number instances and then remove the reference. Check the memory status and you'll see what happens.
    :
    :
    :
    : Kind Regards
    : Konrad
    : ----------------------------
    : (+46/0) 708-70 73 92
    : [email protected]
    : http://konrads.webbsida.com
    :
    :

  • : Well, I did, it does not leak. I seem to get the correct code going in the class sample I posted, if you call Dispose manually, memory is freed and the GC.SupressFinalize call make sure ~Test is not called, if I dont call Dispose, ~Test gets called when GC starts collecting (for example, if I call GC.Collect).

    Great. MS has perhaps succeed creating a really workig GC :-). Not because the one in Java would give me a headache but i've heard of people going bold because over that.

    : I'm wondering why FxCop doesnt like my class! I get this warning:
    : [italic]
    : The Finalize method of 'ConsoleApplication4.MyClass' makes the following calls that are suspect:
    : System.Runtime.InteropServices.Marshal.IsNotWin32Atom(IntPtr)
    : System.Runtime.InteropServices.Marshal.FreeHGlobal(IntPtr)
    : [/italic]
    : And this explaination:
    : [italic]
    : A Finalize method should not call methods other than those in its declaring type or its base type since these are the only objects that are guaranteed to be available (not yet finalized).
    : [/italic]
    : And more info:
    : [italic]
    : Finalizers are not guaranteed to run in any specific order, which means a finalizer that calls a type other than its own or its base type risks calling an object that has already been finalized. This can result in an exception or unpredictable behavior. In either case, the finalizer might leak unmanaged resources.
    : [/italic]
    : How on earth are you supposed to free resources in your finalize if you are not supposed to call any method expect base class members?

    By trusting GC maybe? Perhaps that's what FxCop assumes and "forces" you to use GC.



    Kind Regards
    Konrad
    ----------------------------
    (+46/0) 708-70 73 92
    [email protected]
    http://konrads.webbsida.com

  • [b][red]This message was edited by pingpong at 2002-10-25 5:57:12[/red][/b][hr]
    Konrad,

    I really appreciate your interest in this small matter.

    : : How on earth are you supposed to free resources in your finalize if you are not supposed to call any method expect base class members?
    :
    : By trusting GC maybe? Perhaps that's what FxCop assumes and "forces" you to use GC.
    :

    Well here's the situation:

    The user did not call Dispose manually, the instance of my object is being collected by GC:

    1. If I free my resources in the finalize method, the program doesnt leak but FxCop complains.

    2. If I dont free the resources in the finalize method, FxCop is happy but the program leaks.

    So if I assume step 2 is the correct one (no calling external methods in finalize), the user of my class would have to explicity call Dispose on it, if he doesnt, it leaks.

    All is good in Win32 world, classic resource management, but I thought in the GC world this should not happen, users should not worry about freeing resources themselves.

    Can you recommend any good books on .NET and C# specially?


  • [size=1]: The user did not call Dispose manually, the instance of my object is being collected by GC:
    : 1. If I free my resources in the finalize method, the program doesnt leak but FxCop complains.
    : 2. If I dont free the resources in the finalize method, FxCop is happy but the program leaks.
    :
    : So if I assume step 2 is the correct one (no calling external methods in finalize), the user of my class would have to explicity call Dispose on it, if he doesnt, it leaks.
    [/size]

    About 2) - if the FxCop is happy then it's a very strong sign that the code is right. Now, you say that you get a memory leak then. As far as i see it you shouldn't get it but you can try calling a rebuild finalize(). Rebuild, so that it doesn't call any other methods.

    That way you stop the leak (i hope) and make FxCop happy (i think). But still, it sounds like compromising and i don't like having to compromise with a stupid piece of metal (also silica, plastics and glass).

    : All is good in Win32 world, classic resource management, but I thought in the GC world this should not happen, users should not worry about freeing resources themselves.

    Correct. [b]should[/b] not :-)...

    : Can you recommend any good books on .NET and C# specially?

    Any that's either free downloadable or in a library. Once you've seen ten or fifteen you'll know what's right for you.
    The choice is mainly depending on your expertize level (do you know C/C++/Java/VB) and a little bit on you wallets size.


    Kind Regards
    Konrad
    ----------------------------
    (+46/0) 708-70 73 92
    [email protected]
    http://konrads.webbsida.com

  • No problem on the wallet size, can always right it off as business expense.

    Apart from the FxCop warning, the code works fine, moreever, when I run FxCop on System.Drawing it complained about System.Drawing.Image Dispose/Finalize combo which uses something similar to my code!

    I guess I will stop worrying about it.. I ordered Petzold's Programming Windows with C# and Richter's Applied Microsoft .NET Framework Programming.. These 2 guys should have it all explained :)

    Thank you very much for your input.


  • : No problem on the wallet size, can always right it off as business expense.

    Hire a tutor directly from MS. The only thing you need is a credit card number. They are waiting for your call 24/7. Kind of like a XXX-company only more expensive. I've heard (might be a rumor) that the pricing is over 1000$ an hour in some cases.

    Still feeling "big-wallet" :-)?



    Kind Regards
    Konrad
    ----------------------------
    (+46/0) 708-70 73 92
    [email protected]
    http://konrads.webbsida.com

  • $1000/hour is a little bit beyound my budget!! I will stick to books for now :) Besides, I found this great tool called Anakrino (http://www.saurik.com/net/exemplar/), a great C# decompiler. It worked on 9/10 of DLL's I feed to it only choking on a couple.. Again, it showed source code in Microsoft's own .NET classes that looks exactly like mine.

    I sent an email to the FxCop guys. maybe its a problem in their code not mine. We will see.

    : : No problem on the wallet size, can always right it off as business expense.
    :
    : Hire a tutor directly from MS. The only thing you need is a credit card number. They are waiting for your call 24/7. Kind of like a XXX-company only more expensive. I've heard (might be a rumor) that the pricing is over 1000$ an hour in some cases.
    :
    : Still feeling "big-wallet" :-)?
    :
    :
    :
    : Kind Regards
    : Konrad
    : ----------------------------
    : (+46/0) 708-70 73 92
    : [email protected]
    : http://konrads.webbsida.com
    :
    :

  • : I sent an email to the FxCop guys. maybe its a problem in their code not mine. We will see.

    Good idea. If you remember - let me know if they say anyting smart.



    Kind Regards
    Konrad
    ----------------------------
    (+46/0) 708-70 73 92
    [email protected]
    http://konrads.webbsida.com

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories