浅谈你感兴趣的 CLR GC 机制底层

本文内容是学习CLR.via C#的21章后我的整理,有不足之处欢迎指导。算法

昨天是1024,coder的节日,我为本身coder之路定下一句准则--保持学习,保持自信,保持谦逊,保持分享,越走越远。性能

第一部分—基本原理思想学习

   垃圾回收机制是针对托管堆而言。spa

   不一样于C的运行时堆,托管堆是内存是连续的,每次分配新内存,NextObjPtr指针只须要加上新分配内存块大小便可。C运行时堆为了维护链表的完整性,每当分配新的内存时,遍历链表,一旦发现足够大的内存块,则拆分块,修改节点中的指针。从托管堆中分配内存的速度,几乎能够与线程栈分配相媲美。线程

   GC机制回收的就是托管堆中的垃圾对象。指针

 

第二部分—基本算法思想code

   GC检查托管堆中是否有再也不使用的对象。对象

   那么什么是再也不使用的对象?递归

   首先要解释什么是根(root)。每一个应用程序都有一组根,每一个根都是一个存储位置,其中包含指向引用类型对象的一个指针。该指针要么运用托管堆中的一个对象,要么为null。类型中定义的任何静态字段被认为是一个根,任何方法参数或者局部变量也被认为是一个根。只有引用类型变量,才被认为是根,值类型的变量永远不被认为是根。索引

   GC开始执行时,假设全部对象都是垃圾。

   GC沿着线程栈上检查全部的根,若是发现了一个跟引用堆中的对象,则在这个对象的“同步索引字段”上开启一位,也就是将这个bit设置为1,也就是说这个对象被标记了。

   GC就是这样,以递归的方式遍历全部可达的对象。可达的对象也就是说有根的对象,就是在标记阶段被标记的,也就是本次不回收的。因此不可达的对象就被回收了。

   进入第二阶段--压缩阶段。

   实际上此压缩非彼压缩,在这里是指碎片整理,如何整理呢?若是发现晓得内存块,GC忽略它们,若是发现大的,可用的连续内存块,GC把非垃圾对象移动到这里以压缩堆。

   包含只想这些对象的指针的变量和CPU寄存器,如今都会变得无效,NextObjPtr也应从新指向托管堆的结尾。

  

第三部分—列表和F-reachable队列

   说到终结列表要从某些不只占用内存的对象提及,好比FileStream,它不只占用内存资源,也在占用本地资源。

   Finalize方法就是用于释放本地资源的方法。

   那么这个终结列表用来作什么呢?微软固然不会多此一举,请仔细看好下面这段:

   既占用内存资源,又占用本地资源的,在GC回收这样对象所占的内存时,仅仅回收内存时不够的,由于必定要调用Finalize方法来释放本地资源啊!强烈不建议在代码中咱们手动Finalize,这须要堆Finalize的实现有至关深入而且全面的理解。那么微软的GC是什么怎么来给咱们执行的呢?这就用到了终结列表,为了必定要保证执行Finalize,在最初咱们new操做符分配内存地时候,若是该对象的类型中定义了Finalize方法,那么将该对象的一个指针方法到终结列表当中,当此类对象在托管堆中断定为垃圾的时候,GC扫描终结列表,以查找这些对象的指针,该指针会从终结列表中移除,并追加到F-reachable队列。

   那么这个队列干吗的呢?我认为惟一的目的就是复活对象,并调用Finalize方法释放本地资源(若是对象是死的,咱们没法调用其方法),调用方法的是一个微软定义好的优先级比较高的一个线程,据说这样作有不少好处。那么为何放到F-reachable队列中就复活了?f(finalization)终结,reachable可达的。换言之,可将这个队列看作静态字段那样的一个跟。

  

第四部分—代的思想和原理

   GC机制不管什么时候,都分为三代,0代,1代,2代。

   代是什么,微软关于这个作了假设,新对象生存周期比较短,而老对象倾向于活的久一些。所在代越高的对象,存活的越久,所在代越低的对象,越容易被回收。

   代就是托管堆中被分配的内存而已,也能够说把托管堆分红三部分吧?

   0代初始的预算大小为256kb,当0代中的内存用完时,为新对象分配内存,0代内存不够用时,GC开始回收第一代,未被标记的对象固然回收,已标记的对象则这些对象提升一代,进入1代区域,与此同理,当一代内存已满时,回收1代,此时根对象也就是标记的对象提高至2代。

   再次重点说一下三代预算大小分别为256KB,2MB,10MB,预算大小以提高性能为宜,预算越大,垃圾回收频率越低。再次注意的是,性能提高的理论源于开始的假设:新对象生存期较短,老对象倾向于活的久一些。请仔细看下面一段。

   若是GC回收后,0代存活下来的对象不多,或者说回收的内存不少。0代预算可能会从256调整为128。代的分配空间减小,意味着回收频繁回收频繁,但GC所作的工做会减小,从而减少进程的工做集,最理想的状态是0代对象都是当作垃圾被回收,这样没必要压缩内存,NextObjPtr指向0代起始处。这样来说,最开始的假设是是成立的。

相关文章
相关标签/搜索