2008年6月20日星期五

浅谈Gecko关键部分之二内存分配使用回收

2008年6月17日Firefox3Release版本已正式发布啦,可喜可贺,毕竟经历3年多的努力Mozilla社区终于又能给大家带来一些震撼、新希望,甚至冲动,其中包含很多人性化的东东以及最近几年发展起来的很多有趣的extensions,并且经过一些比较,似乎这个版本部分解决了困扰人们很久的内存使用大多及内存泄漏的问题,是否完全能化解人们心中的疑问可能还有待时间及实践来证明。借助人们很关注的问题,今天也来了解了解相关的内存分配使用回收问题。内存的使用及防止泄漏是c/c++程序员非常关心的问题,一旦有泄漏发生往往都感觉到非常头痛,所以我们也很有必要关心这方面的问题,看看Firefox这些Hacker们究竟是如何来面对这些问题的。

一、内存管理的主要方式
为了尽可能合理高效的使用内存,不同的系统使用了一些各具特色的内存管理机制,1、以java为代表的garbagecollector,所有的资源经由虚拟机来分配、回收,大大降低了java程序员对内存管理的困扰,但也带来了程序速度启动变慢,占用内存较多的问题,特别在程序使用了多种资源后,当然这种机制还在脚本语言如javascript、python、perl等的实现中也得到充分的使用,并且通过一些优化算法,已经达到了很好的效果;2、以linux内核为代表Slab allocation机制,它通过一些缓存及固定长度分配器来有效解决由于多次及不固定长度内存分配可能带来的内存碎片问题;3、以apache为代表的内存池机制,它往往会先malloc一大块内存,以供后续程序内存申请使用,特别在内存分配申请频繁的情况下大大降低程序对系统层的内存申请次数,同时可以起到类似部分garbagecollector的作用。

二、主要Gecko内存管理机制
1、组件的生命周期可简单归纳为首先在factory的createInstance中通过new出一个类实例,然后通过queryInterface进行接口转换及维护mRefCnt,并检查mRefCnt是否为0,如是则delete该实例,主要实现原理可参考XPCOM组件相关开发资料,对应源代码可参考\mozilla\xpcom\glue\nsISupportsImpl.h及\mozilla\xpcom\glue\nsISupportsUtils.h等。当然也有部分类override operator new方法,但往往都是作清零的处理,根本没涉及到更深层的内存管理,而new/delete动作往往分别直接对应系统层的malloc/free方法,所以几乎没有上面提到的垃圾回收、Slab及内存池的使用,当然对javascript的实现是肯定会有相关垃圾回收机制的,但它的出发点往往为了满足脚本语言的要求。

2、对于一些字符串及数组的内存使用往往采用NS_Alloc/NS_Free等,其实现代码对应于XPCom的FrozenFunctions中指定的AllocFunc/FreeFunc,其由\mozilla\nsprpub\pr\src\malloc\Prmem.c中对应的PR_Malloc及PR_Free来实现,其中根据是否使用use_zone_allocator来检查直接调用系统malloc及free还是采取一定类似内存池及slab allocation的方法来统一管理内存的分配。其具体实现代码可详见\mozilla\nsprpub\pr\src\malloc\Prmem.c及Prmalloc.c等。对于NS_Alloc/NS_Free的使用,往往用在一些atoms、tags等当中,总的说来使用不是很多。。

3、为了防止组件之间的循环引用,引入了nsICycleCollector来单独处理这个问题,以尽可能的避免无法释放由于程序逻辑造成的内存冗余,具体实现可参考\mozilla\xpcom\base\nsCycleCollector.cpp;同时为了让程序占系统内存达到一定比例后,采用momory reporter机制要求系统flush/swap一些内存,供程序继续使用;另外结合nsGarbageCollector及nsLeakDetector来扫描stack检测是否存在内存泄漏。

4、网上关于gecko的内存使用的讨论非常多,现提供一些相关资料以供大家参考,从多方面了解gecko内存管理等方面的问题,从自己的角度来了解它,以拓展我们的思路。

没有评论: