微信号:grzlwx

介绍:光荣之路官方资讯

《代码的未来》读书笔记:内存管理与GC那点事儿(二)

2015-10-15 22:18 光荣之路


2.3 引用计数方式

  引用计数方式是GC算法中最简单也最容易实现的一种,其基本原理是:在每个对象中保存该对象的引用计数,当引用发生增减时对计数进行更新。引用计数的增减,一般发生在变量赋值、对象内容更新、函数结束(局部变量不再被引用)等时间点,当一个对象的引用计数变为0时,则说明它将来不会再被引用,因此可以释放响应的内存空间

  下图直观地展示了引用计数方式的大致原理:

  ① 初始阶段:

  ② 引用计数阶段:

  当对象引用发生变化时,引用计数也会跟着变化。在这里,由对象B到对象D的引用失效了,于是对象D的引用计数变为0。由于对象D的引用计数变为了0,因此由对象D到对象C和对象E的引用数也分别相应减少。最后,对象D和对象E引用数变为了0,所以需要被清除。

  ③ 清除阶段:

  所有引用计数变为0的对象都将被释放,“存活”的对象则保留了下来。在整个GC处理过程中,并不需要对所有对象进行扫描。

  引用计数的优点在于:易于实现(标记清除和复制收集机制实现由难度);当对象不再被引用的瞬间就会被释放(其他机制预测一个对象何时被释放很困难)。

  引用计数的缺点在于:

  ① 无法释放循环引用的对象

  ② 必须在引用发生增减时对引用计数做出正确的增减:想想漏掉了对某个对象计数的增减会怎么样?

  ③ 引用计数管理并不适合并行处理:想想如果多个线程同时对引用计数进行增减又会怎样?

三、GC的改良方式

GC的基本算法,大体上都逃不出上述三种方式以及它们的衍生品。现在,通过对这三种方式进行融合,出现了一些更加高级的方式。

3.1 分代回收方式

  由于GC和程序处理的本质是无关的,因此它所消耗的时间越短越好。分代回收的目的是为了在程序运行期间,将GC所消耗的时间尽量缩短。

  分代回收的基本思路是:大部分对象都会在短时间内成为垃圾,而经过一定时间依然存活的对象往往拥有较长的寿命。如果寿命长的对象更容易存活下来,寿命短的对象则会被很快废弃。那么,对分配不久的“年轻”对象进行重点扫描,应该就可以更有效地回收大部分垃圾

  在分代回收方式中,对象会按照生成时间进行分代,刚刚生成不久的年轻对象划为新生代(Young generation),而存活了较长时间的对象划为老生代(Old generation)。对于不同的实现方式,可能还会划分更多的代,

  在.NET中,CLR就将内存中的对象分为了三代,每执行N次0代的回收,才会执行一次1代的回收,而每执行N次1代的回收,才会执行一次2代 的回收。当某个对象实例在GC执行时被发现仍然在被使用,它将被移动到下一个代中上,下图直观地展示了CLR对三个代的回收操作:

  回想刚刚说到的几种基本回收方式,我们可以将其组合一下来为分代回收奠定实现基础。

  (1)首先,从根开始一次常规扫描,找到“存活”对象。这个步骤可以采用标记清除或复制收集,不过大多数分代回收的实现都采用了复制收集算法。不过在扫描的过程中,如果遇到被划分到更高级别的代的对象则不对该对象继续进行递归扫描。这样一来,需要扫描的对象数量就大幅度减少

  (2)其次,将第一次扫描后残留下来的对象划分到更高级别的代上。具体来说,如果是用复制收集算法的话,只要将复制目标空间设置为更高级别的代 就可以。而如果用标记清除算法的话,则大多采用在对象上设置某种级别标志的方式。但是,被分配到更高的级别的代上后,该对象所占用的内存空间的时间也会随 之增加,如何确保及时利用和释放的平衡点也是需要考虑的。

3.2 增量回收方式

  在对实时性要求很高的程序中,往往更重视缩短GC的最大中断时间(想想车辆制动控制程序因为GC而延迟响应的话后果是不堪设想的),必须能够对GC所产生的中断时间做出预测(例如将最多只能中断10ms作为附加条件)。

  因此,为了维持程序的实时性,不等到GC全部完成,而是将GC操作细分成多个部分逐一执行,这种方式就被称为“增量回收”(Incremental GC)。

  由于增量回收的过程是渐进式的,可以将中断时间控制在一定长度之内,另外由于由于中断操作需要消耗一定的时间,GC所消耗的总时间也会增加

3.3 并行回收方式

  在多核环境中,可以通过利用多线程发挥多CPU的性能,并行回收正是通过最大限度地利用多CPU的处理能力来进行GC操作的一种方式。

  并行回收的基本原理是:在原有程序运行的同时进行GC操作。相对于在一个CPU上进行GC任务分割的增量回收来说,并行回收可以利用多CPU的性能,尽可能让这些GC任务并行(同时)进行。

  不过,要让GC操作完全并行并且一点都不影响原有程序的运行是做不到的。因此,在GC操作的某些特定阶段,还是需要暂停原有程序的运行。

四、GC大一统理论

  像标记清除和复制收集之类的算法是从根开始扫描以判断对象生死的算法,被称为跟踪回收(Tracing GC)。而引用计数算法则是当对象之间的引用关系发生变化时,通过对引用计数进行更新来判定对象生死。

  2004年IBM研究中心发表了一篇论文,提出了一个理论:任何一种GC算法都是跟踪回收和引用计数两种方式的组合,两者的关系正如“物质”和“反物质”一样,是相互对立的。对其中一方进行改善的技术之中,必然存在对另一方进行改善的技术,而其结果只是两者的组合而已

参考资料

(1)本文全文源自Ruby之父松本行弘的《代码的未来》一书!

(2)霍旭东,《不得不知的CLR中的GC》【好文一篇,值得阅读】

(3)cposture,《GC/垃圾回收简介

(4)周旭龙,《.NET基础拾遗之内存管理基础

(完)

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。


 
            
 
            
 
            
 
           
 
           
 
           
 
           
 
           
 
           
 
           
 
           
 
           
 
           

感谢作者,传播测试知识、技能与正能量!
欢迎来稿,分享你的测试生活!735821166@qq.com

光荣之路软件测试培训

官网:http://www.gloryroad.cn/

微信公众号:gloryroadtrain

性能测试QQ群:415987441
软件测试招聘QQ群: 203715128
自动化3群QQ: 371211499

 
光荣之路 更多文章 今天晚上的 linux 公开课- Awk 编程 7月28日(今天)晚上的 linux 公开课- shell编程 8月4日(今天)晚上的 linux 公开课- shell编程 9月1日(本周一)晚8点半,光荣之路Web自动化系列基础课—javascript第二讲 推荐本好书《与机器赛跑》
猜您喜欢 很难说服别人?因为没用这个套路! Unity游戏开发丨Android与Unity交互研究 安全从我做起--PHP安全编码 C++11新特性Part8 预测未来 盘点大数据分析领域五大趋势