天天看点

在托管代码中释放托管和非托管资源

IDispose Finalizer
作用 释放托管/非托管资源 释放非托管资源
modifier Public Protected
在C++/CLI的形式 ~ClassName() !ClassName()
在C#2.0的形式 ClassName::Dispose() ~ClassName()

Finalize 方法的使用准则:   l         仅在要求终结的对象上实现 Finalize。存在与 Finalize 方法相关的性能开销。 l         如果需要 Finalize 方法,应考虑实现 IDisposable,以使类的用户可以避免因调用 Finalize 方法而带来的开销。 l         不要提高 Finalize 方法的可见性。该方法的可见性应该是 protected,而不是 public。 l         对象的 Finalize 方法应该释放该对象拥有的所有外部资源。此外,Finalize 方法应该仅释放由该对象控制的资源。Finalize 方法不应该引用任何其他对象。 l         不要对不是对象的基类的对象直接调用 Finalize 方法。在 C# 编程语言中,这不是有效的操作。 l         应在对象的 Finalize 方法中调用基类的 Finalize 方法。     Dispose 方法的使用准则:   l         在封装明确需要释放的资源的类型上实现释放设计方案。用户可以通过调用公共 Dispose 方法释放外部资源。 l         在通常包含控制资源的派生类型的基类型上实现释放设计方案,即使基类型并不需要也如此。如果基类型有 Close 方法,这通常指示需要实现 Dispose。在这类情况下,不要在基类型上实现 Finalize 方法。应该在任何引入需要清理的资源的派生类型中实现 Finalize。 l         使用类型的 Dispose 方法释放该类型所拥有的所有可释放资源。 l         对实例调用了 Dispose 后,应通过调用 GC.SuppressFinalize 方法禁止 Finalize 方法运行。此规则的一个例外是当必须用 Finalize 完成 Dispose 没有完成的工作的情况,但这种情况很少见。 l         如果基类实现了 IDisposable,则应调用基类的 Dispose 方法。 l         不要假定 Dispose 将被调用。如果 Dispose 未被调用,也应该使用 Finalize 方法释放类型所拥有的非托管资源。 l         当资源已经释放时,在该类型上从实例方法(非 Dispose)引发一个 ObjectDisposedException。该规则不适用于 Dispose 方法,该方法应该可以在不引发异常的情况下被多次调用。 l         通过基类型的层次结构传播对 Dispose 的调用。Dispose 方法应释放由此对象以及此对象所拥有的任何对象所控制的所有资源。例如,可以创建一个类似 TextReader 的对象来控制 Stream 和 Encoding,两者均在用户不知道的情况下由 TextReader 创建。另外,Stream 和 Encoding 都可以获取外部资源。当对 TextReader 调用 Dispose 方法时,TextReader 应继而对 Stream 和 Encoding 调用 Dispose,使它们释放其外部资源。   l         考虑在调用了某对象的 Dispose 方法后禁止对该对象的使用。重新创建已释放的对象是难以实现的方案。 l         允许 Dispose 方法被调用多次而不引发异常。此方法在首次调用后应该什么也不做。   -----------MSDN .NET Framework 开发人员指南  《实现 Finalize 和 Dispose 以清理非托管资源》     使用delete关键字删除托管内存中的对象,不能立即将其内存释放掉。而是标注该内存为不再使用的内存,并把指向该内存的句柄释放掉,而其托管内存仍然存在。当关闭应用程序窗口时,统一进行一次垃圾回收,真正释放掉托管堆中内存。   这是我的试验代码

在托管代码中释放托管和非托管资源

using   namespace  System;

在托管代码中释放托管和非托管资源

using   namespace  System::IO;

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

ref   class  Class1: public  IDisposable 

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

... {

在托管代码中释放托管和非托管资源

public:

在托管代码中释放托管和非托管资源

    Class1()

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

    ...{

在托管代码中释放托管和非托管资源

        handle = gcnew array<int>(10000000);

在托管代码中释放托管和非托管资源

        pointer = new int[10000000];

在托管代码中释放托管和非托管资源

    }

在托管代码中释放托管和非托管资源

    ~Class1()

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

    ...{

在托管代码中释放托管和非托管资源

        Console::WriteLine("~Class1() is called!");

在托管代码中释放托管和非托管资源

        File::WriteAllText("c:/text.txt","~Class1() is called!");

在托管代码中释放托管和非托管资源

        delete[] pointer;

在托管代码中释放托管和非托管资源

        delete handle;

在托管代码中释放托管和非托管资源

    }

在托管代码中释放托管和非托管资源

    !Class1()

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

    ...{

在托管代码中释放托管和非托管资源

        Console::WriteLine("!Class1() is called!");

在托管代码中释放托管和非托管资源

        File::WriteAllText("c:/text.txt","!Class1() is called!");

在托管代码中释放托管和非托管资源

        delete[] pointer;

在托管代码中释放托管和非托管资源

        delete handle;

在托管代码中释放托管和非托管资源

    }

在托管代码中释放托管和非托管资源

    //void Dispose() 

在托管代码中释放托管和非托管资源

    //{

在托管代码中释放托管和非托管资源

    //    Console::WriteLine("Dispose() is called!");

在托管代码中释放托管和非托管资源

    //    File::WriteAllText("c:/text.txt","Dispose() is called!");

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

    //}

在托管代码中释放托管和非托管资源

private:

在托管代码中释放托管和非托管资源

    array<int> ^handle;

在托管代码中释放托管和非托管资源

    int* pointer;

在托管代码中释放托管和非托管资源

} ;

在托管代码中释放托管和非托管资源

int  main(array < System::String  ^>   ^ args)

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

... {

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

    Class1 ^object1 = gcnew Class1();

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

    Class1 object2;

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

    delete object1;                //ok

在托管代码中释放托管和非托管资源

//    delete object2;                //error

在托管代码中释放托管和非托管资源

    Console::ReadLine();

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

    return 0;

在托管代码中释放托管和非托管资源

}

在托管代码中释放托管和非托管资源
在托管代码中释放托管和非托管资源

  以下是执行结果: ~Class1() is called!

继续阅读