对象和资源的管理
用了这么长时间的 C++ 架构软件,最头痛的莫过于管理内存中的对象和资源。而在管理对象方面,最难处理的就是删除对象的时机。恐怕很多人早就意识到这一点,所以才有了 gc 技术的蓬勃发展。
当一个对象被很多地方引用的时候,通常我们会给出引用记数,当记数减到 0 的时候就删除,这是个看似完美的解决方案。但是,有多少地方会记得解除引用呢?借助 C++ 的语法糖,可以自动的完成这些工作。长期的引用关系,可以在构造和析构的时候操作;短期的引用,比如就在一个函数内获得对象,操作完毕后马上解除引用。这个时候,可以通过返回几个 warpper 对象来完成。
固然,语法糖可以减少出错的可能,但是,代码还是并隐式的加上了,于之伴随的是运行时性能的下降和代码的膨胀。这个时候,多考虑下设计上的改进会有所收获。
最近两年做的项目,我都趋向于对象统一做删除管理。可以在主线程中安排一个定期时间,扫描所有对象,把需要删除的对象删除。而平时的删除,只是做一个简单的 mark 操作。因为 mark 操作是不可逆的,即不能把一个准备删除的对象 mark 回"不必删除"的状态,所以 mark 操作本身是线程安全,不必加锁的。
为什么这样做?因为对于单种对象或是资源而言,大部分情况都是只读的,很多东西经过初始化后,不再有写操作。即使有,也是 os 保证线程安全的。例如文件 handle , socket 这些。而每个对象都会有一种特殊的操作叫做释放,释放可以看成一种写操作,它导致了对象本身的破坏。当一个对象是完全只读的时候,我们就不需要再考虑它的线程安全问题,就是因为有释放这种操作的存在,破坏了完全只读的特性。当我们把释放提取出来统一放在安全的地方处理的时候,我们就可以让大多数对象完全只读,而不用估计线程安全了。
而且这种做法在单线程环境也是有意义的,用一些简单的技巧(例如用一个指针间接访问对象),甚至不用再使用引用计数。
对于单件的处理,采用静态对象和惰性初始化的方案,简直就是 C++ 程序员的陋习。Double Checked Locking is broken 相信很多人都读过了。过于依赖语法糖,通常就会造成这种结果。其实让程序有明显的初始化和退出阶段,是很容易被规划出来的。把单件(singleton) 的处理放在正确的时机,以正确的次序来处理并非难事。
对于全局所有资源的管理,我个人的主张是一定要考虑采用树结构,而不是线性表。因为扫描所有资源这种操作会比较常见。比如以上提到的扫描所有资源,删除 mark 过的对象。采用树结构的好处是,mark 的时候,可以同时 mark 父节点(对父节点计数)。这样,任何资源树上的任何一支都可以通过 root 知道是否需要遍历分支。通常,删除这种操作并不频繁,通过检查根节点一次就可以忽略整个遍历过程了。
而且删除操作往往是可以并行的。为了在删除过程不影响资源树的结构,我们还可以只是对资源树上的节点置空,再统一压缩掉空指针。这样就可以获得最大效率的删除操作,不至于因为定期删除资源而使服务停顿过久。
Comments
Posted by: Atry | (38) April 10, 2007 09:49 PM
Posted by: Atry | (37) April 10, 2007 09:47 PM
Posted by: Atry | (36) September 19, 2006 03:37 PM
Posted by: TripleX | (35) July 2, 2006 09:10 AM
Posted by: sunway | (34) June 19, 2006 09:12 AM
Posted by: 良少 | (33) June 17, 2006 01:45 PM
Posted by: Detective | (32) June 9, 2006 11:20 PM
Posted by: Cloud | (31) June 9, 2006 07:48 PM
Posted by: KxjIron | (30) June 9, 2006 07:27 PM
Posted by: Cloud | (29) June 7, 2006 06:06 PM
Posted by: KxjIron | (28) June 7, 2006 05:34 PM
Posted by: sunway | (27) June 7, 2006 04:51 PM
Posted by: Cloud | (26) June 7, 2006 02:28 PM
Posted by: KxjIron | (25) June 7, 2006 01:03 PM
Posted by: 清风雨 | (24) June 7, 2006 09:43 AM
Posted by: Cloud | (23) June 6, 2006 04:51 PM
Posted by: Atry | (22) June 6, 2006 03:44 PM
Posted by: Atry | (21) June 6, 2006 03:41 PM
Posted by: sunway | (20) June 6, 2006 03:36 PM
Posted by: analyst | (19) June 6, 2006 03:17 PM
Posted by: Cloud | (18) June 6, 2006 02:11 PM
Posted by: Cloud | (17) June 6, 2006 01:55 PM
Posted by: sunway | (16) June 6, 2006 11:07 AM
Posted by: sunway | (15) June 6, 2006 10:02 AM
Posted by: Atry | (14) June 6, 2006 04:17 AM
Posted by: Cloud | (13) June 5, 2006 07:54 AM
Posted by: analyst | (12) June 5, 2006 12:45 AM
Posted by: Cloud | (11) June 4, 2006 09:22 PM
Posted by: analyst | (10) June 4, 2006 12:11 PM
Posted by: Anonymous | (9) June 3, 2006 11:32 PM
Posted by: Cloud | (8) June 3, 2006 06:09 PM
Posted by: NoSound | (7) June 3, 2006 04:03 PM
Posted by: johal | (6) June 2, 2006 12:24 PM
Posted by: Cloud | (5) May 31, 2006 02:39 PM
Posted by: Ninstein | (4) May 31, 2006 09:19 AM
Posted by: zf | (3) May 31, 2006 09:09 AM
Posted by: DarkSpy | (2) May 30, 2006 07:15 PM
Posted by: cnzhangzhen | (1) May 30, 2006 07:14 PM