关于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的对象。

原文地址:https://www.cnblogs.com/dusf/p/11082190.html

时间: 2024-10-25 08:22:46

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

java: system.gc()和垃圾回收机制finalize

System.gc()和垃圾回收机制前的收尾方法:finalize(收尾机制) 程序退出时,为每个对象调用一次finalize方法,垃圾回收前的收尾方法 System.gc() 垃圾回收方法 class Person{ private int age; private String name; public Person(int age, String name) { this.age = age; this.name = name; } public String toString() { r

Android_对android虚拟机的理解,包括内存管理机制垃圾回收机制。dalvik和art区别

虚拟机很小,空间很小,谈谈移动设备的虚拟机的大小限制 16M ,谈谈加载图片的时候怎么处理大图片的,outmemoryExceptionBitmapFactory.option 垃圾回收,没有引用的对象,在某个时刻会被系统gc掉 . Dalvik和标准Java虚拟机(JVM)首要差别Dalvik 基于寄存器,而 JVM 基于栈.基于寄存器的虚拟机对于编译后变大的程序来说,在它们执行的时候,花费的时间更短.Dalvik和Java运行环境的区别1:Dalvik主要是完成对象生命周期管理,堆栈管理,线

14、Java垃圾回收机制

垃圾回收原理和算法 ??Java引入了垃圾回收机制,令C++程序员最头疼的内存管理问题迎刃而解.Java程序员可以将更多的精力放到业务逻辑上面,而不是内存管量上面,大大的提高了开发效率.这是因为Java有自动的垃圾回收机制. 内存管理 Java 的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放. 对象空间的分配:使用new送键字创建对象即可. 以象空间的释放:将对象赋值null即可.垃圾回收器将负责回收所有"不可达"对象的内存空间. 垃圾回收过程 任何一种垃圾回收算法

详解java垃圾回收机制(转)及finalize方法(转)

详细介绍Java垃圾回收机制 垃圾收集GC(Garbage Collection)是Java语言的核心技术之一,之前我们曾专门探讨过Java 7新增的垃圾回收器G1的新特性,但在JVM的内部运行机制上看,Java的垃圾回收原理与机制并未改变.垃圾收集的目的在于清除不再使用的对象.GC通过确定对象是否被活动对象引用来确定是否收集该对象.GC首先要判断该对象是否是时候可以收集.两种常用的方法是引用计数和对象引用遍历. 引用计数收集器 引用计数是垃圾收集器中的早期策略.在这种方法中,堆中每个对象(不是

垃圾回收机制GC知识再总结兼谈如何用好GC(其他信息: 内存不足)

来源 一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般有如下几种: 1.手动管理:C,C++ 2.计数管理:COM 3.自动管理:.NET,Java,PHP,GO- 但是,手动管理和计数管理的复杂性很容易产生以下典型问题: 1.程序员忘记去释放内存 2.应用程序访问已经释放的内存 产生的后果很严重,常见的如内存泄露.数据内容乱码,而且大部分时候,

java JVM垃圾回收机制

Java语言出来之前,大家都在拼命的写C或者C++的程序,而此时存在一个很大的矛盾,C++等语言创建对象要不断的去开辟空间,不用的时候有需要不断的去释放控件,既要写构造函数,又要写析构函数,很多时候都在重复的allocated,然后不停的~析构.于是,有人就提出,能不能写一段程序在实现这块功能,每次创建,释放控件的时候复用这段代码,而无需重复的书写呢? 1960年 基于MIT的Lisp首先提出了垃圾回收的概念,用于处理C语言等不停的析构操作,而这时Java还没有出世呢!所以实际上GC并不是Jav

垃圾回收机制和数据结构栈链表

1.垃圾回收机制: (1)没有引用变量指向的对象,就是垃圾. 举例: Test t = new Test(); t=null; 那么之前创建的对象就是垃圾. (2)对象没有被使用是另外一种垃圾. new Test(); new Test().toString(); 区别在于第一个对象很明显没有指向,是垃圾.但是第二个不是,因为他被使用了. 2.回收时机. 通常情况下,要在满了的时候回收. 其次在调用 System.gc();//通常情况下会立刻回收.等效于Runtime.getRuntime.g

Java深度历险(四)——Java垃圾回收机制与引用类型

Java语言的一个重要特性是引入了自动的内存管理机制,使得开发人员不用自己来管理应用中的内存.C/C++开发人员需要通过malloc/free 和new/delete等函数来显式的分配和释放内存.这对开发人员提出了比较高的要求,容易造成内存访问错误和内存泄露等问题.一个常见的问题是会产生“悬挂引用(dangling references)”,即一个对象引用所指向的内存区块已经被错误的回收并重新分配给新的对象了,程序如果继续使用这个引用的话会造成不可预期的结果.开发人员有可能忘记显式的调用释放内存

Java的垃圾回收机制笔记

Java的垃圾回收机制笔记 java垃圾回收的意义 确保不再被引用的对象的内存空间被回收. 确保被引用的对象的内存不被错误回收. 再分配内存. java垃圾回收的常用方法 引用计数收集器 堆中的每个对象(不是对象的引用)都有一个引用计数.当一个对象被创建时,给该对象分配一个变量,该变量计数设置设置为1.当任何其他变量被赋值为这个对象的引用,计数加1(a=b,则b引用的对象计数+1),但当一个对象的某个引用超过生命周期或者被设置为一个新值的时候,引用的计数减1(a=c,则a不再指向b指向的对象,而