鉴于复制算法中,没有内存碎片的方式能大大提高分配效率,因此,在mark_sweep的基础上,也可以改良出mark_compact算法,使得空闲空间连续。同时又没有复制算法的无帮吃一半堆的问题。

 

首先是最简单的算法,叫Lisp2算法

 

在标记阶段,不变,仍然是对每个活动对象打上标签。

 

随后,开始移动活动对象到堆的开头。因为没有两个堆,又要挪动对象放到一起,那么forwarding指针便需要在对象头中占用空间(复制算法中不用占用是因为它是非活动对象),且在移动前要做一轮forwarding指针的重指。还要做一轮子对象指针的重指。总体流程如下:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

compaction_phase() {
  set_forwarding_ptr()
  adjust_ptr()
  move_obj()
} 
// 设forward指针最简单set_forwarding_ptr() {
  scan = new_addr = $heap_start  while (scan < $heap_end)    if (scan.mark == TRUE)
      scan.forwarding = new_addr
      new_addr += 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
} 
// 最后,移动对象//不列了,比较简单,只需要扫堆,把活动对象向前移,清除forwarding和mark标记即可

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

网友评论