您的位置:首页 > 其它

火狐的分代垃圾回收机制

2014-10-25 22:37 113 查看
来自 转载请保留地址:http://www.lenky.info/archives/2014/09/2445 或 http://lenky.info/?p=2445
Mozilla Firefox 32.0.3于近几天发布,在Firefox的javascript引擎SpiderMonkey里启用了一个名为分代垃圾回收机制(Generational garbage collection (GGC))的新特性,它的主要作用是用于性能优化。

 简单Mark一下:

 1,原始问题:

 以前的垃圾回收机制是对所有创建的对象进行扫描,判断其是否存活并对已死亡的对象进行回收。如果存活的对象总量并不多,那么这种回收机制没有太大的问题;但是,如果存活的对象总量很多,那么每次进行垃圾回收时,都要去扫描所有的对象,然后判断其是否存活,即便是那些可能从上次扫描到此次扫描的这一段时间没有做过任何改动的对象也会被扫描和判断,因此这无形中就做了很多无用的功夫,性能损耗即在此。

2,改进措施(GGC):

 最直观的改进措施就是把对象进行区别对待,首先是Nursery:每一个新创建的对象属于新生代,在Nursery内存区域分配。当Nursery满时,垃圾回收机制只扫描这一块区域,而根据局部性原理,常规情况下此时大部分新生代对象都已死亡而被回收,而那些依然存活的对象可以被划归老一代,而转存入Tenured区域。经过新生代的回收过滤,Tenured区域的老一代对象的增长就不会那么快,但当Tenured区域满时,同样也将进行垃圾回收。如果把对Nursery区域的扫描称为minor GC,那么对Tenured区域的扫描就可以称为major
GC,很显然,minor GC会经常进行并且较快,而major GC会相对较慢,但执行的次数也会相对较少。简言之,通过把对象进行分代隔开扫描,从而避免了不必要的对象扫描动作,来提升整体回收效率。

3,额外开销:

 既然引入了分代机制,那么就需要增加额外的开销来实现这个逻辑。

 比如:如何判断一个新生代对象是否仍然存活?

 可以这样:通过新生代对象与老一代对象的关联性来进行判断。也就是这样:

 Tenured => Nursery

 即,新生代对象被老一代对象引用着,新生代对象还要被老一代对象所使用,所以此时新生代当然是存活的。比如如果一个新生代对象是作为一个老一代对象的属性被创建,那么它就应该是依然存活的。

通过

 Tenured => Nursery

 来判断新生代对象与老一代对象的关联性是可以的,但具体如何来做?扫描所有的老一代对象来进行检测?这明显不是好办法,因为那会导致每一次minor GC都要进行类似于一次major GC了。

 另外一种方法就是关注每一次对老一代对象的修改,如果发现有对新生代对象的引用操作(比如新引用了一个新生代对象,或修改/删除了对新生代对象的引用等等),就记录下来。这个记录不会太多,因为只需记录从上一次minor GC以来的即可,在进行下一次minor GC时就只需扫描这些记录来判断新生代对象是否存活即可。也就是那些仍被老一代对象所引用的新生代对象是依然存活的,当然,如果一个新生代对象被判断为存活,那么它引用的另外的新生代对象也是存活的,所以在扫描记录的过程中也需要同步的更新记录。

 记录的操作就有一些额外的开销,因此可能在某些情况下,GGC反而会更慢,但在大多数情况下,GGC肯定是足够好的。

4,分配性能:

 GGC可以加速对象分配速度,原理可以大致类似于内存池,比如Nursery区域,除非它已满,否则你可以从上一次分配的末尾处往后取一块空间即可。不用管是否已经使用(因为是未满的Nursery区域,必定是没有使用的),也不用管是否需要释放(所以就没有必要记录相关释放信息,释放会在minor GC统一做)。

 不过对于Tenured区域,对象分配就和以前方式差不多,不过一般情况下,因为Tenured区域的对象比较少,所以就整体性能而言,GGC分配方式相比以前较优。

详细的描述在这里:https://hacks.mozilla.org/2014/09/generational-garbage-collection-in-firefox/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: