在托管代码中释放托管和非托管资源
来源:互联网 发布:网络社区特点 编辑:程序博客网 时间:2024/04/26 11:33
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;
}
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!
- 在托管代码中释放托管和非托管资源
- 托管和非托管资源
- 托管和非托管代码
- 托管和非托管代码
- C# 非托管资源释放
- C#中关于托管资源和非托管资源
- 托管资源和非托管资源
- .net托管资源和非托管资源
- net托管资源和非托管资源
- net托管资源和非托管资源
- 托管资源和非托管资源
- 托管资源和非托管资源
- C# 托管资源和非托管资源
- c# 托管资源和非托管资源
- 托管资源和非托管资源
- C# 托管资源和非托管资源
- C# 托管资源和非托管资源
- C# 托管资源和非托管资源
- ASP.NET生成静态页面实现方法
- 生成静态文件的新闻系统核心代码
- Open source-fantastic!
- 滚动条样式收集
- Asp.net 2.0 中将网站首页生成静态页的一个比较好的方法
- 在托管代码中释放托管和非托管资源
- BAPI / RFC with Delphi(系列之八)--TBAPIControl使用BUS2012建立PO(Delphi源代码)
- GridView使用竅門
- SQL Server连接中的三个最常见错误
- 如何在Ubuntu中卸载老板本的多余内核
- 五种常见的PHP设计模式(择自互联网非本人所写)
- 诱惑无罪~~~
- PetShop4.0 工厂模式及Profile Provider实现(转载)
- P2P之UDP穿透NAT的原理与实现(补充)