来到个新地方,新学习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的对象。