C # calling IDisposable.Dispose () versus creating an object null

Consider the following code:

and. Toy class

class Toy
{
    private string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    private ToyAddon addOn;
    public ToyAddon AddOn
    {
        get { return addOn; }
        set { addOn = value; }
    }

    public void RemoveAddons()
    {
        /*
         * someone said: this could lead to possible memory leak
         * if this class implements IDisposable,
         * then we are not disposing any of the resource 
         * */
        //this.addOn = null; 

        /* instead use this */
        var disposableToyAddOn = this.addOn as IDisposable;
        if (disposableToyAddOn != null)
            disposableToyAddOn.Dispose();

        this.addOn = null;

    }
    public override string ToString()
    {
        return String.Format("{0}, {1}",
            this.name, 
            (this.AddOn == null) ? "" : addOn.AddOnName);
    }
}

      

B. Toy Addon

class ToyAddon
{
    private string addOnName;

    public string AddOnName
    {
        get { return addOnName; }
        set { addOnName = value; }
    }

}

      

C. Main program

class Program
{
    static void Main(string[] args)
    {
        ToyAddon tAdd = new ToyAddon();
        tAdd.AddOnName = "Amazing AddOn";
        Toy t = new Toy();

        t.Name = "Amazing Toy";
        t.AddOn = tAdd;
        t.RemoveAddons();

        Console.WriteLine(t.ToString());


    }
}

      

Now I was asked to check if the "having-a" object implements IDisposable, then call the dispose method. (please see the comments in the Toy class)

IMHO, if I make the reference null, then the object on the heap will be marked for Collection by GC.

It would be helpful if this can be done, about what happens on the heap and stack, and about the GC's role in what if a class (like ToyAddOn) implements IDisposable vs if it doesn't.

+3


source to share


4 answers


Now I was asked to check if the "have-a" object is implementing IDisposable, then call the dispose method.

IDisposable

is a pattern that is used to release unmanaged resources that must be explicitly released as the GC is unaware of them. Typically, the class that holds the unmanaged resources also implements a finalizer, and for that, it actually extends the lifespan of the object more than necessary. Dispose

in such situations, it usually calls a call GC.SupressFinalize

to remove the specified object from the finalization queue.

This is usually a good pattern if you have an object IDisposable

to implement IDisposable

yourself to make sure the underlying resource is disposed of.

IMHO if I make the reference null then the object on the heap will be marked for Collection by GC.



If the member you want to "exclude" is not a member static

, then (usually) there is no reason to do so. The compiler is smart enough to optimize it and the GC is smart enough to know that there is no more reference to the variable and clear it up.

Edit:

As @ScottChamberlain points out, there are times when a one-off object is still holding a reference and hence the GC does not consider it a GC. When you remove it and zero it out, you are hinting to the GC that it is "ready to collect".

+2


source


Unless you manually dispose of the class, the unmanaged resources (if any) it is holding will only be cleaned up when the GC detects that there is enough memory pressure to warrant garbage collection and the object is GCed and Finalized.

Not all things that need to be scrapped add memory pressure, they can cling to things like Window Handles.

If the memory pressure never gets high enough, you probably never garbage collect these values โ€‹โ€‹before you run out of the resource it is throwing out. You see this a lot when people put Bitmap in a tight loop but don't use it, each bitmap uses a GDI + descriptor and doesn't account for managed memory pressure and doesn't trigger GC. This often causes people to get OutOfMemoryExceptions when they still have a lot of memory, because the real thing they ended up with was GDI + processing.



By explicitly disposing of your resources, you don't have to "hope you're lucky" and your object will be completed before you run out of unmanaged resources that it was holding.

The stack and the heap have nothing to do with this.

+1


source


A sample try-casting something IDisposable

and getting rid of it if it implements that interface is very indicative of a design flaw. If the reference code type does not implement IDisposable

, this is a very strong indication that:

  • Owners of this type of link should not control it; even if derived types do implement Disposable

    , it should be the responsibility of the code that instantiated those types (and contains references to those types) to clean them up.

  • The base type must implement IDisposable

    (even if 99% of the implementations do nothing) because some instances will have a lifetime outside the control of anyone who knows if they really need to be cleaned up. A prime example of these latter situations is IEnumerator<T>

    . Although IEnumerator

    omitted IDisposable

    , the need for it became apparent shortly after graduation; when Microsoft added IEnumerator<T>

    , they included IDisposable

    directly. While most implementations IEnumerator<T>

    can be eliminated without cleanup, there is no way that the code calling GetEnumerator

    on the collection has no way of knowing if the implementation IEnumerator<T>

    might be one of the rare ones that need to be cleaned up, and there is no practical way when IEnumerable<T>

    , the way that GetEnumerator

    createsIEnumerator<T>

    , can be known when the client will be executed with it, so no one but the client can Dispose

    IEnumerator<T>

    .

Determine if all the instances ToyAddOn

that implement can Disposable

end their lives while the only references are kept in code that has no idea if they need cleanup. If so, do ToyAddOn

implement Disposable

. If not, leave the cleanup for code that knows it's necessary.

+1


source


I agree with these three answers. To simplify the answer to your question:

/ * * someone said: this could lead to a possible memory leak * if this class implements IDisposable, * then we do not dispose of any of the resources * * / //this.addOn = null;

What someone said doesn't really apply to your example. But this is absolutely correct, in general.

Suppose the Toy class lives much longer than ToyAddon. The ToyAddon class subscribes to events in the Toy Class. If so, ToyAddon must unsubscribe in the Dispose method. If you have not called the ToyAddon Dispose method after removing it from the Toy instance, the ToyAddon instace will live in memory as long as the Toy instance is alive.

And even if you call Dispose in the above case, there is still a reference to ToyAddon via 'addOn'. Therefore, in order to get rid of it completely, you need to set addOn to null.

IMHO if I make the reference null then the object on the heap will be marked for Collection by GC.

Right in your case, wrong, as I explained above.

+1


source







All Articles