.Net中,垃圾回收器负责回收你创建的引用类型的对象,但是回收时间并不能准确估计出来,所以这称之为非确定销毁。值类型自动释放,所以不在本文讨论之中。
但是有些稀缺资源,比如文件句柄、数据库连接等,就需要尽快释放。如何做到呢。最简单的方法就是调用GC.Collect ()强迫垃圾回收器工作。但是这种方法会降低性能,除非迫不得已。
那么有没有更好的办法?
“析构函数”
“析构函数”与c++析构函数的区别
“析构函数”怎么样?比如下面的例子:
class Class1
{
public Class1()
{
Console.WriteLine("constructor");
}
~Class1()
{
Console.WriteLine("destructor");
}
}
其实c#中的“析构函数”并不是c++程序员心中的析构函数,在c++中,跳出对象所生存的堆栈时或者调用delete的时候,析构函数就会被调用。c#提供了一种语法相近,但是语义完全不同的“析构函数”.实际上,该函数只是重载了System.Object类的Finalize函数。
System.Object是c#中所有的类型的基类型,由于是隐式派生,所以不需要在派生列表中指定它。Finalize函数的访问权限是protected,只能被自己和派生类使用,实际上在垃圾回收器销毁对象时,将会给该对象一次调用Finalize的机会,这样我们可以将自己需要的逻辑放在“析构函数”里面。如果对象构造期间出现异常,则该方法也会被调用。
但是,经过以上分析,可以看出,“析构函数”并不能让我们确定销毁某对象。
“析构函数”的危害
顺便说一下,C#代码应该总是使用“析构函数”,而不是手动重载Finalize函数,因为“析构函数”会自动将内部代码放到try块内,并且在finnally块内部调用base.Finalize方法。
“析构函数”正常情况下是不建议创建的,因为它会提升该类以及被引用的其他类的代龄,这会导致垃圾回收器过早的运行,从而影响性能,同时每次垃圾回收器工作时都要额外的调用“析构函数”,这显然也是对性能有影响的,如无必要,就不要为自己的类创建“析构函数”。
更严重的情况,如果A类有“析构函数”,B类有“析构函数”,A有一个B类的变量,当垃圾回收器工作时,A和B的“析构函数”调用顺序却没有得到保证。这样会导致错误,这比性能问题更严重。
Oh,my!尽量不要在“析构函数”里面访问托管成员变量,除非销毁非托管资源。但是通常非托管资源都需要确定销毁,显然这时不能用“析构函数”解决问题。
GC.SuppressFinalize ( )将阻止Finalize被调用。
IDisposable接口
不如提供一个方法,该方法能够将需要提前释放的资源释放掉,然后该对象可以到垃圾回收器工作的时候再释放。这就是Dispose方法。
class Class1:IDisposable
{
public Class1()
{
GC.SuppressFinalize(this);
Console.WriteLine("constructor");
}
~Class1()
{
Console.WriteLine("destructor");
}
public void Dispose()
{
GC.SuppressFinalize(this);
Console.WriteLine("Dispose");
}
}
GC.SuppressFinalize(this);这句话告诉垃圾管理器,从现在开始,不准调用我的“析构函数,当然不能调,因为我的Dispose后面还要执行清理资源的代码,垃圾回收器如果抢在前面将对象回收,就会出错。如果类没有实现“析构函数”,当然就不需要这句话了。
Close方法
为了适应大多数程序员的习惯,可以添加一个Close方法,其实内部只是调用了Dispose而已。不高兴的话,也可以懒得实现它。
Using 方法
为了减少编写异常处理代码,using语法可以保证无论是否发生异常,都为调用Dispose方法或者Close方法,前提是对象支持Idisposable接口。所以这是一个很简洁的语法。
分享到:
相关推荐
从上面的章节中可以知道,当服务器每次的往返过程,都将销毁页面并重新创建新的页面。如果一个页面中的信息超出了页面的生命周期,那么这个页面中的相关信息就不存在了。如果注销了页面的信息,那么用户的一些信息...
3.4.3 销毁窗体 3.4.4 定位窗体 3.4.5 绘图 3.4.6 消息处理 3.5 小结 第4章 CObject类 4.1 概述 4.2 创建对象 4.2.1 直接构造 4.2.2 使用new操作符 4.3 诊断功能 4.3.1 Dump成员 4.3.2 AssertValid ...
Session_End 销毁session时候触发 Application_Error IIS请求流程 Http请求到达IIS服务器后,HttpRunTime作为入口,HttpRunTime类的ProcessRequest方法。HttpRunTime包含着所有的Http请求信息(ProcessRequest方法 ...
一、Java基础知识 1.Java有那些基本数据类型,String是不是基本...这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() ...
确定您是否有足够的内存来处理数据。 从可用的内存中获取一部分内存。 向可用内存池(pool)中返回部分内存,以使其可以由程序的其他部分或者其他程序使用。 实现这些需求的程序库称为分配程序(allocators),...
与cgi的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。...
兼容ASP.Net Forms SWFUpload v2 延续了SWFUpload的设计目标,将UI分离以交给开发人员控制和后续扩展 概述 传统的HTML上传 标准的HTML上传表单为用户提供一个文本框和按钮来选择文件,选中的文件是随着form表单...
与cgi的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。...
PrimaryKey 通过主键来确定成员,该主键指的是成员表中的主键,该主键同时要与 Dimension 里设置的 foreignKey 属性对应的字段形成外键对应关系 primaryKeyTable 如果成员表不只一个,而是多个表通过 join 关系...
因 此在赋值后应该及时销毁或者初始化 L2,以免发生不可预见的错误。 比较 使用 Contains 方法。 ArrayList Array1=new ArrayList(); Array1.Add("as"); bool b1=Array1.Contains("as"); MessageBox.Show(b1....