心寄笔端 附庸风雅

甘草的技术博客

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

MGCR, More about garbage  collection related.

Section 1, Why GC.

为什么要GC呢?

在UNIX和C之前,早在Lisp的时代,就有GC了,GC就是Garbage Collection,垃圾回收(机制)。据说,Lisp所以支持GC,是因为:“内存管理太重要了,所以不能由程序员自己来管理。”。而随着UNIX的胜利,C语言也胜利了,C语言所以不支持GC,是因为:“内存管理太重要了,所以一定要由程序员自己来管理。”
上个世纪(其实就是10几年前的事情),Java的成功,使得GC又重新焕发了光彩。

GC,真的慢嘛?

确实慢,

  1. 在1950-1970,甚至此后很长时间,GC都被认为是极大地影响速度的因素。
  2. 某些GC算法是导致效率底的原因。例如引用计数就是一种自以为是的算法(后面讨论)。
  3. GC导致了程序运行的停顿,这种不流畅使得GC在实时系统中难以被信任。

确实不慢,

  1. 相当多的程序,在没有进行GC之前,已经不辱使命的结束了,那么对于C++程序员来说,可以理解为只new了,没有delete,反正进程的结束,delete的,没有delete的,都化为乌有了。
  2. 现代的GC算法,例如Mark Sweep,已经证明比Ref Count快了。
  3. 而且GC算法有很多优化的空间。例如JVM就有关于GC的调优手段。【1】

而且随着硬件的发展,速度将不再是问题,GC将成为主流,目前,C++09也在新的标准中加入了关于GC的支持,这在最后讨论,毕竟这是最复杂的了。既然无所谓“所谓的”效率低下了,那么既然有选择GC的理由。

  1. 开发效率将大大的提高。
  2. 由于开发者的疏漏而造成的内存泄露将大大地减少。
  3. 软件开发中的抽象度将提高。
  4. 模块之间的耦合降低了。
  5. 程序的接口更清晰了。

本文中的GC,只要是现代GC,而不包含引用计数技术,但是既然算是早期的GC手段之一,还是要在这里先批判一下的。而且为后面的叙述进行知识上的普及。
老实说,我以为不了解引用计数的C++程序员,一定是一个不合格的程序员。毕竟在C++里有太多引用计数的存在了。

  1. 早期版本的stl string类,往往是采用引用计数和COW技术实现的。但是现在往往是单纯的内存copy完成了,毕竟内存条总在降价。
  2. 在Boost,Loki的实现中,也存在相当数量依靠引用计数计数的实现。
  3. C++的构造函数和析构函数机制,也为大量使用引用计数打开了方便之门。
  4. 整个COM体系,就是以引用计数为基础的,每一个COM程序员都知道在什么时候AddRef,在什么时候Release,尽管要在无数次痛苦的Debug后才知道哪里不符合COM的调用确定了。【2】
  5. 在Windows编程中,许多内核对象,就是采用引用计数的方式进行管理的。

 

引用计数,并非一无是处的,我打算提几个优点后,再次批判它:尽管引用计数的实现非常简单,移动,并且不会造成系统运行的不流畅(它将GC的消耗,分摊的每一个对象的引用变化上了)。但是GC有两个非常致命的问题存在,第一,GC在循环引用的问题上是无能为力的【3】。第二。引用计数在多线程中,必须进行同步,而同步的消耗是非常大的,这也就是COM为什么要搞出来套间的原因之一。【4】

 

 注:

【1】:参考 http://www.douban.com/group/topic/4450520/

【2】:以下是我从其他地方搜到的,也没有校对就Paste了,貌似和我研究COM的时候,看到的条目不差什么。

1、启动组件得到一个接口指针(Interface)后,不要调用AddRef()。因为系统知道你得到了一个指针,所以它已经帮你调用了AddRef()函数;
2、通过QueryInterface()得到另一个接口指针后,不要调用AddRef()。因为......和上面的道理一样;
3、当你把接口指针赋值给(保存到)另一个变量中的时候,请调用AddRef();
4、当不需要再使用接口指针的时候,务必执行Release()释放;
5、当使用智能指针的时候,可以省略指针的维护工作。

【3】:先审核代码如下:

        //Scope 
        {
            A t1 
= new A();
            A t2 
= new A();
            
            t1.another 
= t2;
            t2.another 
= t1;
        }

我们尽管认为这是依靠引用计数的某种语言的代码片段,或者你当它就是COM对象,当两个对象走出Scope的时候,它们的引用计数却都不为0,那么t1和t2都不会被delete了,那么,也就是造成了内存泄露。

【4】:参看《COM本质论》。

更多需要注释的内容,在后面会被讨论。

posted on 2009-01-08 10:13  甘草  阅读(321)  评论(0编辑  收藏  举报
Baidu
Google
心寄笔端
TEST
以后我会加上Power By的,先别介意