关于C#的垃圾回收机制,Finalize和Dispose的区别(自认为很清晰了,有疑问的评论)

Posted dusf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于C#的垃圾回收机制,Finalize和Dispose的区别(自认为很清晰了,有疑问的评论)相关的知识,希望对你有一定的参考价值。

来到个新地方,新学习C#,前面看到C#的垃圾回收,Finalize和Dispose时,总是一知半解,迷迷糊糊。这次好了,前面连续两次面试问到这个问题,脑子里不是很清晰,加上用英文来表达,更是雪上加霜的感觉。

 

回来,好好看了相关资料,从网上看,总没有人能说的很清晰,往往很深奥的样子,拿了本<C# language 7.0>,这样中英文结合看,总算清晰了。

现在主要是找工作,没有时间写详细,先就说个重点:

1. 垃圾回收器GC负责托管对象的回收。GC通过应用根对象(如全局变量,静态变量等)能否访问到来判断对象是否能回收。

而不是通过引用计数法来判断对象是否需要被回收,因为引用计数无法结局一个循环引用的两个对象的回收,他们的引用计数都为1,但实际这两个对象是整个应用程序中的孤岛对象,

应用程序根对象无法访问到,应该被回收。

2. 垃圾回收很耗性能,一般只在分配新对象发现空间不够用时才触发回收。具体回收时采用的算法是分步回收,即分代回收的方法,其基于统计原理。新产生的对象总是有最大的可能性被废弃不再使用,比如调用函数中的新分配的局部对象;而经过几次回收周期中存活下来的对象,则更不可能被回收掉,如全局变量等。

  GC初始化默认每个对象都是需要回收的,回收触发时,检测根对象是否能访问到来判断对象是否真的可以回收。GC将对象标签为3代,分别是0,1,和2代对象。0代是还没有经过一次回收检测的对象,1代表示经过一次回收检测后存活下来(即不能回收)的对象,而2代表示经过2次以上检测仍存活的对象。

 GC检测依照顺序,分别检测0代,1代和2代。但是如果检测到0代,回收部分对象后,发现空间已经足够新对象使用,回收检测立刻停止。如果仍然不够,才会继续检测1代对象,直至2代对象。通过这样的方法,避免垃圾回收机制产生作用时的性能消耗。大部分情况下,0代检测都足以起效。

 

1. C#中的Object,Class和reference的关系

Object是Class的一个实例,而Reference是一个指针。学过C/C++的很好理解,实际其内容是一个内存地址,该内存地址里存放的是实际的对象。

C#中所有的类的实例化都是通过引用实现,实际是使用new 来实例化一个类。如下举例说明:

class Program

  static void Main(string[] args)
  
    Console.WriteLine("***** GC Basics *****");
    // Create a new Car object on the managed heap. We are returned a reference to this object ("refToMyCar").
    Car refToMyCar = new Car("Zippy", 50);
    // The C# dot operator (.) is used to invoke members on the object using our reference variable.
    Console.WriteLine(refToMyCar.ToString());
    Console.ReadLine();
  

其中变量refToMyCar实际就是一个引用,一个指针,指向实际的实例对象Car("Zippy", 50)

在C#中,引用refToMyCar和实例对象Car("Zippy", 50)是存放于不同的内存块中,分别叫做堆栈区和托管内存堆区;

技术图片

程序的堆栈区是一个临时数据区,存放函数调用的对象,局部变量等,函数调用完存放于堆栈区的对象的生命期就结束了,每个线程都有固定大小的堆栈。

而堆是一个全局内存区,所有分配在Managed Heap的对象,需要管理何时释放。在C/C++语言中,这部分数据需要显示的delete和new配套使用,而在C#中,会被.NET CLR来管理,就是说你在托管堆中只管生成新的实例,而不用管该实例占用空间的释放,这由CLR自动管理,实际就是垃圾回收器干的事情。

2. 垃圾回收器(GC)

 GC是怎样知道一个对象不在使用了呢,这涉及到后面描述的具体算法,简而言之就是GC发现,无法从代码根应用到达的对象。可以以一个不太严谨的解释来理解,就是该分配在堆区的

对象,已经没有外部引用了。如下一段代码:

static void MakeACar()

  // If myCar is the only reference to the Car object, it *may* be destroyed when this
  method returns.
  Car myCar = new Car();

Car的对象在函数外,没有可以引用到,就意味着该对象可以被回收了。

3.

C#有两类对象,托管和非托管对象。这个托管指的是对象被谁管理,在.net框架里,就是被CLR托管。非托管对象,指的是一些操作系统提供的资源,比如文件句柄,Socket,数据库连接等。

这些资源对象的使用,需要像操作系统申请并且使用完后,及时的归还。比如C#的FileStream类,我们使用时有如下一段代码:

FileInfo finfo = new FileInfo(FilePath);
//以打开或者写入的形式创建文件流
using (FileStream fs = finfo.OpenWrite())
...
//根据上面创建的文件流创建写数据流
StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.Default);
//把新的内容写到创建的html页面中
sw.WriteLine(strhtml);
sw.Flush();
sw.Close();

其中,finfo, fs, sw三个分别为FileInfo,FileStream,StreamWriter的对象。

 

以上是关于关于C#的垃圾回收机制,Finalize和Dispose的区别(自认为很清晰了,有疑问的评论)的主要内容,如果未能解决你的问题,请参考以下文章

java 怎么对一个对象强制垃圾回收

Java开发中垃圾回收的最佳做法?

finalize方法

9.垃圾回收机制和JVM

java垃圾回收机制整理

java有自动垃圾回收机制