垃圾收集的那点事(E)

垃圾收集的那点事(E)

cache_flush算是这个库最糟糕的一段代码了,总共有100多行,缩进糟糕,做很多不同的工作。我就纳闷,为什么不抽些子函数出来,这样的代码基本上不具备维护价值,因为自己重写一次,比搞明白这个函数有趣多了。
由于这个函数实在太长,所以不一次全贴上来,一部分一部分的看吧。

qsort(E.cache,CACHE_SIZE, sizeof ( struct  cache_node),cache_node_cmp);

// ----------------------------------------
static   int
cache_node_cmp(
const   void   * a, const   void   * b)
{
    
const struct cache_node *ca=(const struct cache_node *)a;
    
const struct cache_node *cb=(const struct cache_node *)b;
    
if (ca->parent != cb->parent) {
        
return cb->parent - ca->parent;
    }

    
if (ca->parent == -1 ) {
        
return 0;
    }

    
return (ca->child & ~ UNSET_MASK) - (cb->child & ~UNSET_MASK);
}
首先,对 E.cache进行排序,比较子是cache_node_cmp。
return cb->parent - ca->parent ,是用 cb减去ca的,因此首先根据parent_id进行降序排序。注意,在这一比较结果中,如果ca->parent = -1,那么比较结果为正,空闲节点ca往数组右边移动;如果cb->parent = -1,那么比较结果为负,空闲节点cb还是会处在数组右边。
为什么要注意这个呢?因为本次排序的一个结果就是,那些空闲节点都集中到了cache数组的右边,只要遍历cache的过程中遇到了第一个空闲节点,那么剩下的必然都是空闲节点了。
当然要达成这个排序结果,还需要下面的这步, if (ca->parent == -1 ) {return 0;}
比较子的最后一句,在parent_id相同的情况下,按child_id升序排序。

E.cache经过排序后,呈现出以下状况:
1.根据parent_id呈降序排序,并且parent_id相同的节点紧挨在一起
2.空闲的cache节点全部都排在了数组的右边
3.parent_id相同的节点,按child_id升序排序

     while  (i < CACHE_SIZE)  {

        
if (parent==-1{
            
return;
        }
排序之后,就是遍历有序的cache数组。可以看到排序的效果了,当parent_id = -1的时候,就只剩下空闲的cache_node,因此可以退出遍历。

        head =& E.cache[i];
        next
= head;
        sz
= 0 ;

        
while  (next -> parent  ==  parent  &&  i < CACHE_SIZE)  {
            sz 
+= 1 - UNSET_MASK_BIT(next->child);
            
++next;
            
++i;
        }
这一段代码,是统计同一parent_id下child的数目。因为有些child_id被标记了 UNSET_MASK,因此这种cache节点就不用统计到总数中了。其中 UNSET_MASK_BIT是位移操作,如果child被标记了UNSET_MASK,那么位移的结果就是1,1-1=0,也就没有统计到总数中了。

struct  node  * node =& E.pool[parent];
children
= node -> u.n.children;
统计了parent拥有的child之后,接下来就是要把这些child记录到parent的数据结构上了。这里不得不回顾一下 struct node的定义,上次看的时候,并没有探讨 struct link *children是做什么的,现在可以看看link的定义
struct  link  {
    
int number;
    
int children[1];
}
;
这个结构就是parent用来记录其所有child_id的地方。其中number用来记录child的总数量,而children则是一个整数数组,用来记录所有的child_id。
cache_flush剩下的操作,就是把新的child_id添加到children中去,当然其中包含其他一些细节处理。这里先把这些东西交代清楚,因为其后的代码将是比较难以理解的,我仍不是十分的明白。

你可能感兴趣的:(垃圾收集的那点事(E))