C# GC 垃圾回收机制原理

转载参照自以下文章:

http://www.cnblogs.com/fdyang/p/3456258.html (c#) 销毁资源和释放内存
https://www.cnblogs.com/Jessy/articles/2552839.html C# Finalize和Dispose的区别
https://www.cnblogs.com/wuyuankun/p/4103620.html C#中标准Dispose模式的实现


1,什么是资源:
所谓的资源就是程序中可利用的数据,譬如:字符串、图片和任何二进制数据,包括任何类型的文件。


2,访问资源的步骤:
1)分配内存:分配一定的内存空间。
2)  初始化内存: 一个类型的实例构造器负责这样的初始化工作。
3)使用资源: 通过访问类型成员来使用资源。根据需要会有反复。
4)销毁资源: 执行清理工作。
什么是托管资源,非托管资源:托管资源是由CLR全权负责的资源,CLR不负责的资源位非托管资源。
对于托管资源通过GC自动清理回收。对于非托管资源,通过代码调用手动进行清除,再由GC回收。
如何正确的释放资源:对于非托管的资源,一般就是,Stream(流),数据库的连接,网络连接等的这些操作系统资源,需要我们手动去释放。

Net提供了三种释放方法:Dispose,Close,析构函数(也就是Finalize方法)

第一种:提供Close方法:
介绍:关闭对象资源,在显示调用时被调用。
Close 表示什么意思,它会不会释放资源,完全由类设计者决定。因为Close方法是不存在的。你不写就没有。那为什么要加一个Close方法呢?为了避免不熟悉C#语法的开发人员更直观的释放资源,因此提供了Close方法。提供一个Close方法仅仅是为了更符合其他语言(如C++)的规范。正常情况Close方法里面会调用Dispose()方法。

第二种:Dispose
继承IDisposable接口,实现Dispose方法;
介绍:调用Dispose方法,销毁对象,需要显示调用或者通过using语句,在显示调用或者离开using程序块时被调用。
Dispose方法用于清理对象封装的非托管资源,而不是释放对象的内存,对象的内存依然由垃圾回收器控制。
Dispose方法调用,不但释放该类的非托管资源,还释放了引用的类的非托管资源。
Dispose模式就是一种强制资源清理所要遵守的约定;Dispose模式实现IDisposable接口,从而使得该类型提供一个公有的Dispose方法。
疑问1:Dispose内部到底如何去清理资源的?

第三种:析构函数(也就是Finalize方法)
一个正常情况的类是不会写析构函数的,而一旦一个类写了析构函数,就意味着GC会在不确定的时间调用该类的析构函数,判断该类的资源是否需要释放,然后调用finalize方法,如果重写了finalize方法则调用重写的finalize方法。
Finalize方法的作用是保证.NET对象能在垃圾回收时清除非托管资源。
在.NET中,Object.Finalize()方法是无法重载的,编译器是根据类的析构函数来自动生成Object.Finalize()方法的
finalize由垃圾回收器调用;dispose由对象调用。
finalize无需担心因为没有调用finalize而使非托管资源得不到释放,因为GC会在不确定时间调用,当然,你也可以手动调用finalize方法,而dispose必须手动调用。
finalize虽然无需担心因为没有调用finalize而使非托管资源得不到释放,但因为由垃圾回收器管理,不能保证立即释放非托管资源;而dispose一调用便释放非托管资源。
只有类类型才能重写finalize,而结构不能;类和结构都能实现IDispose.原因请看Finalize()特性。

虽然可以手动释放非托管资源,我们仍然要在析构函数中释放非托管资源,这样才是安全的应用程序。否则如果因为程序员的疏忽忘记了手动释放非托管资源, 那么就会带来灾难性的后果。所以说在析构函数中释放非托管资源,是一种补救的措施,至少对于大多数类来说是如此。 
由于析构函数的调用将导致GC对对象回收的效率降低,所以如果已经完成了析构函数该干的事情(例如释放非托管资源),就应当使用SuppressFinalize方法告诉GC不需要再执行某个对象的析构函数。 
析构函数中只能释放非托管资源而不能对任何托管的对象/资源进行操作。因为你无法预测析构函数的运行时机,所以,当析构函数被执行的时候,也许你进行操作的托管资源已经被释放了。这样将导致严重的后果。 
在结构上重写Finalize是不合法的,因为结构是值类型,不在堆上,Finalize是垃圾回收器调用来清理托管堆的,而结构不在堆上。
带有析构函数的类,生命周期会变长。内存空间需要两次垃圾回收才会被释放,导致性能下降。
一个带有析构的类,它引用了很多其他的类,这将导致这些类都升到第1代。(gc有0,1,2三代回收机制)。

5)释放内存:托管堆上的内存由GC全权负责, 值引用的在栈上的内存会随着栈空间的消亡而自动消失。
GC.Collect(); //强制对所有代进行即时垃圾回收
当应用程序代码中某个确定的点上使用的内存量大量减少时,在这种情况下使用 GC.Collect 方法可能比较合适。

疑问2:
垃圾回收机制的原理?强制垃圾回收是怎么一回事?

 

3,释放模式:是一种微软建议的写法,先手动显示去释放资源,如果忘记了,再让finalize释放资源。如果dispose调用了,则析构不会再调用(使用SuppressFinalize方法取消析构函数的调用)。

 

其他:
如果引用类型对象不再需要,是否需要显式=null;答案是:即使不这样做,GC也会进行垃圾回收。

你可能感兴趣的:(内存结构,操作系统,c#技术)