在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
今天我的一个朋友看到我写的那篇《C#中用AJAX验证用户登录》时,给我指出了点小毛 病。就是在用户登录时,如果用户登录失败,在下面这段代码中,都会new出来一个User对象,如果连续登录失败多次,就会生成多个User对象,而它们 在登录失败后已经无用了,依然占据着内存,就算是C#有垃圾回收机制,但不确定什么时候对这些对象进行回收。
}
首先,我们需要明确2个概念。
第一个就是很多人用.Net写程序,会谈到托管这个概念。那么.Net所指的资源托管到底是什么意思,是相对于所有资源,还是只限于某一方面资源?很多人对此不是很了解,其
实.Net所指的托管只是针对内存这一个方面,并不是对于所有的资源;因此对于Stream,数据库的连接,GDI+的相关对象,还有Com对象等等,这
些资源并不是受到.Net管理而统称为非托管资源。而对于内存的释放和回收,系统提供了GC-Garbage
Collector,而至于其他资源则需要手动进行释放。 接下来说说这三个函数的调用时机,我用几个试验结果来进行说明,可能会使大家的印象更深。 对于Close来说不属于真正意义上的释放,除了注意它需要显示被调用外,我在此对它不多说了。而对于析构函数而言,不是在对象离开作用域后立刻被执行,只有在关闭进程或者调用GC.Collect方法的时候才被调用,参看如下的代码运行结果。
CallGC();
运行的结果为: 显然在出了Create函数外,myClass对象的析构函数没有被立刻调用,而是等显示调用GC.Collect才被调用。
using( DisposeClass myClass = new DisposeClass() )
如上运行的结果如下: 那么对于如上DisposeClass类型的Dispose实现来说,事实上GC还需要调用对象的析构函数,按照前面的GC流程来说,GC对于需要调用析构函数的对象来说,至少经过两个步骤,即首先调用对象的析构函数,其次回收内存。也就是说,按照上面所写的Dispose函数,虽说被执行了,但是GC还是需要执行析构函数,那么一个完整的Dispose函数,应该通过调用GC.SuppressFinalize(this )来告诉GC,让它不用再调用对象的析构函数中。那么改写后的DisposeClass如下: 通过如下的代码进行测试。 运行的结果如下:
显然对象的析构函数没有被调用。通过如上的实验以及文字说明,大家会得到如下的一个对比表格。
那么在定义一个类型的时候,是否一定要给出这三个函数地实现呢。
我的建议大致如下。
<!--[if !supportLists]-->1.<!--[endif]-->提供析构函数,避免资源未被释放,主要是指非内存资源;
<!--[if !supportLists]-->2.<!--[endif]-->对于Dispose和Close方法来说,需要看所定义的类型所使用的资源(参看前面所说),而决定是否去定义这两个函数;
<!--[if !supportLists]-->3.<!--[endif]-->在实现Dispose方法的时候,一定要加上“GC.SuppressFinalize( this )”语句,避免再让GC调用对象的析构函数。
C#程序所使用的内存是受托管的,但不意味着滥用,好地编程习惯有利于提高代码的质量以及程序的运行效率。
|
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论