开发者

how to ensure no memory leak in the following case

开发者 https://www.devze.com 2023-01-28 08:04 出处:网络
If a class has开发者_运维知识库 a property which contains unmanagedresources. How to make sure no memory leak when using the class

If a class has开发者_运维知识库 a property which contains unmanaged resources. How to make sure no memory leak when using the class

Class A
{
         B {get; set;}
}

B contains unmanaged resources.


Implement IDisposable and clean up your unmanaged resources by calling Dispose(), preferably placing the call to Dispose in a finally statement so you clean up resources even in the case of an exception.

C# has a using keyword that you can employ to make sure that the Dispose method is called, even if an exception is thrown.

EDIT: Incorporated call to GC.SuppressFinalize and finalizer implementation per Ran's answer

class A : IDisposable
{
    private bool _disposed;

    ~A()
    {
        this.Dispose(false);
    }

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                // dispose managed resources
            }

            // clean up unmanaged resources

            _disposed = true;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        using (var someInstance = new A())
        {
            // do some things with the class.
            // once the using block completes, Dispose
            // someInstance.Dispose() will automatically
            // be called
        }
    }
}


Using IDisposable might not be enough, because it relies on the user remembering to call Dispose or to use using etc.

For a complete solution, combine IDisposable and a finalizer. Like this:

Edit: Made some corrections in the Dispose method based on SpeksETC's comment.

class MyClass : IDisposable
{
    ~MyClass() 
    {
        Dispose(false);
    }

    public void Dispose()
    {
        GC.SupressFinalize();
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposing)
        {
            // clear unmanaged resources here (can only be called once)
            ...
        }

        // dispose called explicitly by the user, clean up managed resources here
        ...
    }
}

This ensures that native resources will always be cleared, even if the user forgets to call Dispose, while still allowing the user to clear the resources early.

The if inside the Dispose implementation is needed because if this class is being finalized, you may not call Dispose on your members because they may have been GC'ed already.


I think it is important to point out that B is a managed resource that only contains unmanaged resources.

Therefore, A should implement IDisposable and dispose of B in its Dispose() method, but does not need a finalizer since it doesn't have any unmanaged resources to clean up - the finalizer needs to be implemented within B itself. Even if you implemented a finalizer it would call a Dispose that looked like this:

protected virtual void Dispose(bool disposing) 
    { 
        if (disposing) 
        { 
            // dispose called explicitly by the user, clean up managed resources here 
            b.Dispose() 
        } 

        // no unmanaged resources to clean up so do nothing which makes Finalizer unneccesary
        ... 
    } 


SpeksEtc is correct in that if B contains unmanaged resources then B should ensure there are no leaks not A.

But what are the unmanaged resources and would the SafeHandle class help? Then B would contain a SafeHandle which would contain the unmanaged resource and you wouldn't need to worry about it.

0

精彩评论

暂无评论...
验证码 换一张
取 消