ParalletScavenge:复制算法,多线程,关注吞吐率

Copying GC(GC复制算法):

最早是Robert R.Fenichel和Jerome C.Yochelson提出,简略说将空间分为From和To,当From空间齐全占满时,gc将流动对象全副复制到To空间,复制实现后,From和To的使命调换。

为了保障From中所有活着的对象都能复制到To里,要求From和To空间大小统一。

coping(){  free = to_start;  for(r : roots){    *r = copy(*r)  }  swap(from_start,to_start)}/***free设在To空间的结尾*第四行copy函数,复制能从根援用到的对象及其子对象,返回*r所在的新空间。*而后替换From和To,对From空间进行gc*/ copy(obj){  if(obj.tag != COPIED){    copy_data(free,obj,obj.size);    obj.tag = COPIED;    obj.forwarding = free;    free = obj.size     for(child : children(obj.forwarding){      *child = copy(*child)    }  }  return obj.forwarding}/***obj.tag 并不是独自的一个域,只是占用了obj的field1,一旦obj被复制结束,其在From空间的域值更改没有关系*obj.forwarding也不是一个独自的域,占用了obj.field2,用来标识新空间的地位* 由更上可知,须要每个对象至多有两个域* 深度遍历*/

//调配new_obj(size){  if(free + size > from_start + HEAP_SIZE /2){    copying(); //空间有余,gc    if(free + size > from_start + HEAP /2){       allocation_fail();//还是不够,调配失败    }  }  obj = free;  obj.size = size;  free += size;  return obj;}

copying算法的总结:

1 copying算法的工夫复杂度只跟沉闷对象的个数无关,能够在较短时间内实现gc,吞吐量较高

2 调配速度快,挪动指针,不波及闲暇链表

3 不会产生碎片,复制的行为自身蕴含了压缩

4 深度优先,具备援用关系的对象靠在一起。利于缓存的应用(局部性原理)。

5 堆的利用率低

6  递归的进栈出栈耗费比迭代的模式大,但用迭代的模式是广度优先,jdk以前是广度,当初都是深度;有进阶算法能够近似靠近深度优先而不须要递归

 Parallel Old:标记-整顿,多线程

Mark Compact GC 标记-压缩算法:

首先看Donald E.Knuth钻研进去的Lisp2算法:

compaction_phase(){  set_forwarding_ptr();  adjust_ptr();  move_obj();} set_forwarding_ptr(){  scan = new_address = heap_start;  while(scan < heap_end){  //第一次搜寻堆    if(scan.mark == TRUE){  //被标记为活对象      scan.forwarding = new_address;//new_address指向挪动后的地址      new_address += scan.size;    }    scan += scan.size; //扫描下一个活对象  }} adjust_ptr(){  for(r : roots){    *r = (*r).forwarding;  }    scan = heap_start;  while(scan < heap_end){  //第二次搜寻堆    if(scan.mark = TRUE){      for(child : children(scan))        *child = (*child).forwarding    }    scan += scan.size;  }} move_obj(){  scan = free = heap_start;  while(scan < heap_end){//第三次搜寻堆     if(scan.mark = TRUE){        new_address = scan.forwarding;        copy_data(new_address,scan,scan.size);        new_address.forwarding = null;        new_address.mark = FALSE:        free += new_address.size;        scan += scan.size;     }  }}

总结:

1 堆利用率高

2 压缩空间,没有碎片

3 工夫耗费大:须要搜寻三次堆,且工夫与堆大小成正比

还有一个Two-Finger算法,能够做到只搜寻两次,但要求所有对象整顿成大小统一,这个束缚比拟刻薄,jvm用的应该是Lisp2。

分代垃圾回收:

可行性来源于教训:“大部分的对象在生成后很快就变成了垃圾,很少有对象能活得很久”

有些GC算法的工夫是和活着的对象的个数成正比,比方标记-革除MarkSweep,复制Copying;

minorGC:新生代GC,minor指小规模的;

majorGC:老年代GC

promotion:新生代对象通过若干次gc仍活着的晋升为老年代。

Ungar的分代垃圾回收:David Ungar钻研进去的将copying算法与分代思维联合

 1  堆划分为4个空间:生成空间new_start,2个大小相等的幸存空间survivor1_start,survivor2_start,老年代空间old_start

    2个幸存空间相似于copying gc中的From和To,每次利用生成空间+1个幸存空间,gc后活着的对象复制到另一个幸存空间

2  思考:新生代gc:须要思考老年代空间对新生代空间中对象的援用

Remembered Set & Card Table


Remembered Set:实现局部垃圾收集时(partial gc),用于记录从非收集局部指向收集局部的指针的汇合的 形象数据结构了。

在分代垃圾回收里,Remembered Set 用来记录老年代对象 对  新生代对象 的跨代援用;在regional collector中,Remembered Set 用来记录跨region的指针。

粒度;数据结构;写屏障

3 对象的降职

 MaxTenuringThreshold 定义了降职老年代的对象的最大年龄,大于这个年龄,肯定会降职,小于这个年龄,也有可能降职,取决于TargetSurvivorRatio。

当年龄为age的对象的大小之和超过了targetSurvivorratio * survivor,则理论用来判断是否降职的年龄是这个动静的age,不是maxtenuringthreshold