.net GC垃圾回收机制工作原理(转)

首先了解一下托管资源--.net所指的托管只是针对内存这一块,并不是对于所有的资源;针对Stream,数据库的连接,com对象,GDI+的相关对象等,这些对象并不受.net的管理成为非托管资源;对于内存的回收和管理,由GC完成,而其它资源则需要手动释放。

其次垃圾的定义--.Net类型分为两大类,一个就是值类型,另一个就是引用类型。前者是分配在栈上,并不需要GC回收;后者是分配在堆上,因此它的内存释放和回收需要通过GC来完成。GC的全称为“Garbage Collector”,顾名思义就是垃圾回收器,那么只有被称为垃圾的对象才能被GC回收。也就是说,一个引用类型对象所占用的内存需要被GC回收,需要先成为垃圾。那么.Net如何判定一个引用类型对象是垃圾呢,.Net的判断很简单,只要判定此对象或者其包含的子对象没有任何引用是有效的,那么系统就认为它是垃圾。

明确了这两个基本概念,接下来说说GC的运作方式以及其的功能。内存的释放和回收需要伴随着程序的运行,因此系统为GC安排了独立的线程。那么GC的工作大致是,查询内存中对象是否成为垃圾,然后对垃圾进行释放和回收。那么对于GC对于内存回收采取了一定的优先算法进行轮循回收内存资源。其次,对于内存中的垃圾分为两种,一种是需要调用对象的析构函数,另一种是不需要调用的。GC对于前者的回收需要通过两步完成,第一步是调用对象的析构函数,第二步是回收内存,但是要注意这两步不是在GC一次轮循完成,即需要两次轮循;相对于后者,则只是回收内存而已。

垃圾回收算法 – 分代(Generation)算法

代是CLR垃圾回收器采用的一种机制,它唯一的目的就是提升应用程序的性能。分代回收,速度显然快于回收整个堆。

CLR托管堆支持3代:第0代,第1代,第2代。第0代的空间约为256KB,第1代约为2M,第2代约为10M。新构造的对象会被分配到第0代。

如上图所示,当第0代的空间满时,垃圾回收器启动回收,不可达对象(上图C、E)会被回收,存活的对象被归为第1代。

当第0代空间已满,第1代也开始有很多不可达对象以至空间将满时,这时两代垃圾都将被回收。存活下来的对象(可达对象),第0代升为第1代,第1代升为第2代。

实际CLR的代回收机制更加“智能”,如果新创建的对象生存周期很短,第0代垃圾也会立刻被垃圾回收器回收(不用等空间分配满)。另外,如果回收了第0代,发现还有很多对象“可达”,并没有释放多少内存,就会增大第0代的预算至512KB,回收效果就会转变为:垃圾回收的次数将减少,但每次都会回收大量的内存。如果还没有释放多少内存,垃圾回收器将执行完全回收(3代),如果还是不够,则会抛出“内存溢出”异常。

也就是说,垃圾回收器会根据回收内存的大小,动态的调整每一代的分配空间预算!达到自动优化!

总结

.NET垃圾回收器的基本工作原理是:通过最基本的标记清除原理,清除不可达对象;再像磁盘碎片整理一样压缩、整理可用内存;最后通过分代算法实现性能最优化。

经过前面的介绍,可以知道析构函数只能被GC来调用的,那么无法确定它什么时候被调用,因此用它作为资源的释放并不是很合理,因为资源释放不及时;但是为了防止资源泄漏,毕竟它会被GC调用,因此析构函数可以作为一个补救方法。而Close与Dispose这两种方法的区别在于,调用完了对象的Close方法后,此对象有可能被重新进行使用;而Dispose方法来说,此对象所占有的资源需要被标记为无用了,也就是此对象被销毁了,不能再被使用。例如,常见SqlConnection这个类,当调用完Close方法后,可以通过Open重新打开数据库连接,当彻底不用这个对象了就可以调用Dispose方法来标记此对象无用,等待GC回收。明白了这两种方法的意思后,大家在往自己的类中添加的接口时候,不要歪曲了这两者意思。

----------------------------------以下是CSDN上一位高手的总结----------------------------------------------

1、Finalize方法(C#中是析构函数,以下称析构函数)是用于释放非托管资源的,而托管资源会由GC自动回收。所以,我们也可以这样来区分 托管和非托管资源。所有会由GC自动回收的资源,就是托管的资源,而不能由GC自动回收的资源,就是非托管资源。在我们的类中直接使用非托管资源的情况很 少,所以基本上不用我们写析构函数。 
2、大部分的非托管资源会给系统带来很多负面影响,例如数据库连接不被释放就可能导致连接池中的可用数据库连接用尽。文件不关闭会导致其它进程无法读写这个文件等等。

实现模型: 
1、由于大多数的非托管资源都要求可以手动释放,所以,我们应该专门为释放非托管资源公开一个方法。实现IDispose接口的Dispose方法是最好的模型,因为C#支持using语句快,可以在离开语句块时自动调用Dispose方法。 
2、虽然可以手动释放非托管资源,我们仍然要在析构函数中释放非托管资源,这样才是安全的应用程序。否则如果因为程序员的疏忽忘记了手动释放非托管资源, 那么就会带来灾难性的后果。所以说在析构函数中释放非托管资源,是一种补救的措施,至少对于大多数类来说是如此。 
3、由于析构函数的调用将导致GC对对象回收的效率降低,所以如果已经完成了析构函数该干的事情(例如释放非托管资源),就应当使用SuppressFinalize方法告诉GC不需要再执行某个对象的析构函数。 
4、析构函数中只能释放非托管资源而不能对任何托管的对象/资源进行操作。因为你无法预测析构函数的运行时机,所以,当析构函数被执行的时候,也许你进行操作的托管资源已经被释放了。这样将导致严重的后果。 
5、(这是一个规则)如果一个类拥有一个实现了IDispose接口类型的成员,并创建(注意是创建,而不是接收,必须是由类自己创建)它的实例对象,则 这个类也应该实现IDispose接口,并在Dispose方法中调用所有实现了IDispose接口的成员的Dispose方法。 
只有这样的才能保证所有实现了IDispose接口的类的对象的Dispose方法能够被调用到,确保可以手动释放任何需要释放的资源。

时间: 2024-08-30 07:30:08

.net GC垃圾回收机制工作原理(转)的相关文章

Java GC(垃圾回收)的工作原理

Garbage Collection简称GC,是垃圾回收的意思. 内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃.Java语言提供的GC功能可以自动检测对象是否超过作用域,从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法,资源回收工作全部交由GC来完成,程序员不能精确控制垃圾回收的时机. 下面简要介绍一下GC在实现垃圾回收时的基本工作原理. Java的内存管理实际上就是对象的管理,其中包括对象的分配和释放.对于程序员来说,

面试官,不要再问我“Java GC垃圾回收机制”了

Java GC垃圾回收几乎是面试必问的JVM问题之一,本篇文章带领大家了解Java GC的底层原理,图文并茂,突破学习及面试瓶颈. 楔子-JVM内存结构补充 在上篇<JVM之内存结构详解>中有些内容我们没有讲,本篇结合垃圾回收机制来一起学习.还记得JVM中堆的结构图吗? 图中展示了堆中三个区域:Eden.From Survivor.To Survivor.从图中可以也可以看到它们的大小比例,准确来说是:8:1:1.为什么要这样设计呢,本篇文章后续会给出解答,还是根据垃圾回收的具体情况来设计的.

C# GC 垃圾回收机制

今天来谈谈C# 的GC ,也就是垃圾回收机制,非常的受教,总结如下 首先:谈谈托管,什么叫托管,我的理解就是托付C# 运行环境帮我们去管理,在这个运行环境中可以帮助我们开辟内存和释放内存,开辟内存一般用new ,内存是随机分配的,释放主要靠的是GC 也就是垃圾回收机制.哪么有两个大问题 1.GC 可以回收任何对象吗?2.GC 什么时候来回收对象?回收那些对象? 对于第一个问题,GC 可以回收任何对象吗?我是这样理解的,首先要明白一点,C# 在强大也管不到非托管代码?哪么什么是非托管代码呢?比如s

GC垃圾回收机制

个人理解: 因为在使用JAVA创建一个类或者对象后,难免会存在以后不使用的情况,为了减少其继续再占用内存,必须建立一套清理垃圾的机制,但是怎么判断什么样的才算是不使用的垃圾呢,这里面进行了判断并标记分类,然后根据不同的标记再进行不同的处理.不过世事无完美之说,其也是存在弊端的(开销通常很大,而且它的运行具有不确定性),为了避免,我们还是在正常工作中,养成一个好的编程习惯.详情参照https://www.cnblogs.com/jeffwongishandsome/p/talk-about-GC-

Asp.Net中的GC(垃圾回收机制)

1.群里讨论中扯出来点,先记录下来关于GC的一些认识 建立一个测试项目. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace GC_Test { class Program { static void Main(string[] args) { //托管代码.被CLR管理的代码 //非托管代码.不被

GC垃圾回收机制,iOS内存管理。

问题: MRC中通过调用静态方法创建的新对象,不再使用时需要对其发送release消息吗? 不需要,因为约定静态方法创建的对象会自动将其放入自动释放池,即已对其发送autorelease消息,因此不可再对其进行手动释放.MRC中静态方法创建新对象的实现模板如下: 问题: NSRangeException, EXC_BAD_ACCESS, 僵尸对象, 野指针,空指针? NSRangeException: 常见于数组越界. EXC_BAD_ACESS: 野指针问题(内存泄漏), 调用了已经释放的对象

Java GC - 垃圾回收机制

1.简介 对于Java developer来说,了解JVM GC工作原理能够帮助我们开发出更优秀的应用,同时在处理JVM瓶颈时能够更加自由.在最近一年的应用开发中能体会到这些知识带来的好处,并且让我们的应用在较大规模的并发时能够良好的工作. 本文部分知识和图片来源于书籍<Java Performance> - Charlie Hunt & Binu John 著,该书全面讲解了Java 应用的性能分析.优化点与JVM原理等知识,本文(以及稍候的一些文章)只包含 GC collector

asp.net 之 GC (垃圾回收机制)

今天抽时间好好整理了下GC相关知识,看了CSDN和博客园的几篇文章,有了一定的简单了解,特整理一份. 提到GC,与托管代码和非托管代码密不可分. 1.托管代码:无需也无法人为干预内存回收工作的代码,会自动调用GC进行垃圾回收,我们日常所写的研发程序代码大多数都是分托管代码,没有终结器(Finalize). 像简单的int,string,float,DateTime等等,.net中超过80%的资源都是托管资源. 2.非托管资源:与托管代码形成对立面,这部分资源虽然垃圾回收器可以跟踪封装非托管资源的

Android内存优化1 了解java GC 垃圾回收机制3

引言 接App优化之内存优化(序), 作为App优化系列中内存优化的一个小部分. 由于内存相关知识比较生涩, 内存优化中使用到的相关工具, 也有很多专有名词. 对Java内存管理, GC, Android内存管理, Dalvik/ART等知识有一个理论的认识, 可以让我们更好的使用这些工具, 分析内存问题. 据此, 我们就先从理论入手, 聊聊GC那些事儿. 1, 何为GC GC 是 garbage collection 的缩写, 垃圾回收的意思. 也可以是 Garbage Collector,