.NET 的GC

什么是GC

Garbage Collector(垃圾收集器)以应用程序的root为基础,遍历应用程序在Heap上动态分配的所有对象,通过识别它们是否被引用来确定哪些对象是已经死亡的哪些仍需要被使用。已经不再被应用程序的root或者别的对象所引用的对象就是已经死亡的对象,即所谓的垃圾,需要被回收。这就是GC工作的原理。

为了实现这个原理,GC有多种算法。比较常见的算法有Reference Counting,Mark Sweep,Copy Collection等等。目前主流的虚拟系统.net CLR,Java VM和Rotor都是采用的Mark Sweep算法。

托管堆中存放引用类型对象,因此GC的内存管理的目标主要都是引用类型对象。

GC与内存管理

一个对象的生命周期简单概括就是:创建>使用>释放,在.NET中一个对象的生命周期:

  • new创建对象并分配内存
  • 对象初始化
  • 对象操作、使用
  • 资源清理(非托管资源)
  • GC垃圾回收

创建一个新对象的主要流程

image

GC垃圾回收

  • GC 0/1/2代:代龄(Generation);
  • 大对象堆(Large Object Heap),大于85000字节的大对象会分配到这个区域,这个区域的主要特点就是:不会轻易被回收;就是回收了也不会被压缩(因为对象太大,移动复制的成本太高了);
  • 垃圾:没有被引用的对象

垃圾回收的基本流程

1.标记:根据应用程序根指针Root遍历堆上的每一个引用对象,对于还在使用的对象(可达对象)进行标记

2.清除:针对所有无引用对象进行清除,针对普通对象直接回收内存,而对于实现了终结器的对象(实现了析构函数的对象)需要单独回收处理。清除之后,内存就会变得不连续了,就是步骤3的工作了。

3.压缩:把剩下的对象转移到一个连续的内存,因为这些对象地址变了,还需要把那些Root跟指针的地址修改为移动后的新地址。

扫描二维码关注公众号,回复: 6495523 查看本文章

关于代龄(Generation)

  • 第0代,最新分配在堆上的对象,从来没有被垃圾收集过。任何一个新对象,当它第一次被分配在托管堆上时,就是第0代(大于85000的大对象除外)。 
  • 第1代,0代满了会触发0代的垃圾回收,0代垃圾回收后,剩下的对象会搬到1代。 
  • 第2代,当0代、1代满了,会触发0代、1代的垃圾回收,第0代升为第1代,第1代升为第2代。

非托管资源回收

  .NET中提供释放非托管资源的方式主要是:Finalize() 和 Dispose()。

Dispose():

常用的大多是Dispose模式,实现IDisposable接口,Dispose需要手动调用,在.NET中有两中调用方式:

//方式1:显示接口调用
SomeType st1=new SomeType();
//do sth
st1.Dispose();

//方式2:using()语法调用,自动执行Dispose接口
using (var st2 = new SomeType())
{
    //do sth
}

using只是一种语法形式,本质上还是try…finally的结构

Finalize() :终结器(析构函数)

  它作用就是用来释放非托管资源,由GC来执行回收,因此可以保证非托管资源可以被释放。

  它是来自System.Object中受保护的虚方法Finalize,无法被子类显示重写,也无法显示调用。

所有实现了终结器(析构函数)的对象,会被GC特殊照顾,GC的终止化队列跟踪所有实现了Finalize方法(析构函数)的对象。

  • 当CLR在托管堆上分配对象时,GC检查该对象是否实现了自定义的Finalize方法(析构函数)。如果是,对象会被标记为可终结的,同时这个对象的指针被保存在名为终结队列的内部队列中。终结队列是一个由垃圾回收器维护的表,它指向每一个在从堆上删除之前必须被终结的对象。
  • 当GC执行并且检测到一个不被使用的对象时,需要进一步检查“终结队列”来查询该对象类型是否含有Finalize方法,如果没有则将该对象视为垃圾,如果存在则将该对象的引用移动到另外一张Freachable列表,此时对象会被复活一次。
  • CLR将有一个单独的高优先级线程负责处理Freachable列表,就是依次调用其中每个对象的Finalize方法,然后删除引用,这时对象实例就被视为不再被使用,对象再次变成垃圾。
  • 下一个GC执行时,将释放已经被调用Finalize方法的那些对象实例。

GC在哪些情况下回进行回收工作?

  • 内存不足溢出时(0代对象充满时)
  • Windwos报告内存不足时,CLR会强制执行垃圾回收
  • CLR卸载AppDomian,GC回收所有
  • 调用GC.Collect
  • 其他情况,如主机拒绝分配内存,物理内存不足,超出短期存活代的存段门限

感谢:https://www.cnblogs.com/anding/p/5260319.html

猜你喜欢

转载自www.cnblogs.com/lqyy/p/11028416.html
GC