近似深度优先搜索方法

Paul R.Wilson、Michael S.Lam、Thomas G.Moher,1991

这个方法只是近似深度优先搜索,但可以做到深度优先执行GC复制算法。

Cheney的GC复制算法

假设所有对象都是2个字,下图所示是对象间的引用关系。

下图所示是执行该算法时候,各个对象所在的页面(页面,在操作系统,和计算机组成原理课程中都有)。

右上角数字是页面编号,假如说页面容量是6个字(只能放3个对象)。

从上图不难看出,A,B,C是相邻的,这就是比较理想的状态。对于其他对象来说,降低了连续读取的可能性,降低了缓存命中率。

在下面1-4页中,同一个页面的对象甚至都没有引用关系(页面1中D和页面2中HI,有引用关系,但是不命中,需要读内存数据到catch),这样就不得不从内存上再去读。一直这样下去可想而知,有很多的对象会是这样的分布状态。

前提

在这个方法中有下面四个变量。

  • $page: 将堆分割成一个个页面的数组。$page[i]指向第i个页面的开头。
  • $local_scan:将每个页面中搜索用的指针作为元素的数组。$local_scan[i]指向第i个页面中下一个应该搜索的位置。
  • $major_scan:指向搜索尚未完成的页面开头的指针。
  • $free:指向分块开头的指针。

先复制A到To空间,然后复制他们的孩子B,C,都被放置到了0页。如下图示:

  • 因为A已经搜索完毕,所以$local_scan[0]指向B。
  • $free指向第一页的开头,也就是说下一次复制对象会被安排在新的页面。在这种情况下,程序会从$major_scan引用的页面和$local_scan开始搜索。
  • 当对象被复制到新页面时,程序会根据这个页面的$local_scan进行搜索,直到新页面对象被完全占满为止。
  • 此时因为$major_scan还指向第0页,所以还是从$local_scan[0]开始搜索,也就是说要搜索B。

  • 复制了D(B引用的对象),放到了$page[1]开头。像这样的页面放在开头时候,程序会使用该页面的$local_scan进行搜索。此时$local_scan[0]暂停,$local_scan[1]开始。之后复制了H,I。

  • 这里第一页满了,所以$free指向第二页开头。因此$local_scan[1]暂停搜索,程序$local_scan[0]开始搜索。(即对B对象再次进行搜索,看有没有其他孩子。)

  • 可以看到B的孩子E被复制到了$page[2],同样,对$local_scan[0]再次进行暂停,对E用local_scan[2]进行搜索。
  • 因此复制了J,K。

  • 通过对J,K的搜索页面2满了,$free指向了页面3。再次回到$local_scan[0]进行搜索。
  • 搜索完对象C,复制完A到O的所有对象之后状态如下图所示。

这样就搜索完了第0页($major_scan),虽然还没有搜索完子对象,但是孩子没有孩子,所以现在这个状态,和搜索完后是一样的。

执行结果

该方法是如何安排对象的呢?如下图示:

很明显能看出与Cheney的复制算法不同,不管下一个页面在哪里,对象之间都存在引用关系。

该方法,采用了不完整的广度优先,它实际上是用到了暂停的。从一开始我们就根据关系,然后进行暂停,将有关系的对象安排到了一个页面中。

多空间复制算法

GC复制算法最大的缺点就是只能利用半个堆。

但是如果我们把空间分成十份,To空间只占一份那么这个负担就站到了整体的1/10。剩下的8份是空的,在这里执行GC标记清除算法。

多空间复制算法,实际上就是把空间分成N份,对其中两份进行GC复制算法,对其中(N-2)份进行GC标记-清除

multi_space_copying()函数

muti_space_copying(){
$free = $heap[$to_space_index]
for(r :$roots)
*r = mark_or_copy(*r) for(index :0..(N-1))
if(is_copying_index(index) == FALSE)
sweep_block(index) $to_space_index = $from_space_index
$from_space_index = ($from_space_index +1) % N
}

将堆分为N等份,分别是$heap[0],$heap[1]...$heap[N-1]。这里的$heap[$to_space_index]表示To空间,每次执行GC时,To空间都会像$heap[0],$heap[1]...$heap[N-1],$heap[0],这样进行替换。Form空间在To空间的右边,也就是$heap[1]...$heap[N-1]。

  • 其中第一个for循环,为活动对象打上标记。能看出来是标记清除算法中的一个阶段。
  • 其中第一个for循环,当对象在From空间时,mark_or_copy()函数会将其复制到To空间,返回复制完毕的对象。如果obj在除Form空间以外的其他地方mark_or_copy()会给其打上标记,递归标记或复制它的子对象。
  • 其中第二个for循环,是清除阶段。对除From和To空间外的其他空间,把没有标记的对象连接到空闲链表。
  • 最后将To和From空间向右以一个位置,GC就结束了。

mark_or_copy()

mark_or_copy(obj){
if(is_pointer_to_from_space(obj) == True)
return copy(obj)
else
if(obj.mark == FALSE)
obj.mark == TRUE
for(child :children(obj))
*child = mark_or_copy(*child)
return obj }

调查参数obj是否在From空间里。如果在From空间里,那么它就是GC复制算法的对象。这时就通过copy()函数复制obj,返回新空间的地址。

如果obj不在From空间里,它就是GC标记-清除算法的对象。这时要设置标志位,对其子对象递归调用mark_or_copy()函数。最后不要忘了返回obj。

copy()

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 = mark_or_copy(*child)
return obj.forwarding
}

递归调用不是copy()函数,而是调用mark_ or_copy()函数。如果对象*child是复制对象,则通过mark_or_copy() 函数再次调用这个copy()函数。

执行过程

将内存分为4等份。如下图示:

To空间$heap[0]空着,其他三个都被占用。这个状态下,GC就会变为如下如示:

我们将$heap[0]作为To空间,将$heap[1]作为From空间执行GC复制算法。此外$heap[2]和$heap[3]中执行GC标记-清除算法,将分块连接到空闲链表。

当mutator申请分块时候,程序会从空闲链表或者$heap[0]中分割出块给mutator。

接下来,To空间和From空间都向后移动一个位置。mutator重新开始。

这次$heap[1]是To空间,$heap[2]From空。这种状态下执行就会变为下图所示:

$heap[2]的活动对象都被复制到了$heap[1]中,在$heap[0]和$heap[3]中执行GC标记清除。然后From和To后移一次。

优缺点

优点

提高内存利用率:没有将内存空间二等分,而是分割了更多空间。

缺点

GC标记清除,分配耗时,分块碎片化。当GC标记清除算法的空间越小的时候,该问题表现的越不突出。例如将内存分为3份的情况下。

Copying GC (Part two :Multi Space Copying GC)的更多相关文章

  1. 深入JVM系列(二)之GC机制、收集器与GC调优

    一.回想JVM内存分配 须要了解很多其它内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配 2.大对象直接进入老年代  3.长期存活的 ...

  2. 深入JVM系列(二)之GC机制、收集器与GC调优(转)

    一.回顾JVM内存分配   需要了解更多内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配2.大对象直接进入老年代 3.长期存活的对象 ...

  3. java gc的工作原理、如何优化GC的性能、如何和GC进行有效的交互

    java gc的工作原理.如何优化GC的性能.如何和GC进行有效的交互 一个优秀的Java 程序员必须了解GC 的工作原理.如何优化GC的性能.如何和GC进行有效的交互,因为有一些应用程序对性能要求较 ...

  4. 源码分析HotSpot GC过程(三):TenuredGeneration的GC过程

    老年代TenuredGeneration所使用的垃圾回收算法是标记-压缩-清理算法.在回收阶段,将标记对象越过堆的空闲区移动到堆的另一端,所有被移动的对象的引用也会被更新指向新的位置.看起来像是把杂陈 ...

  5. 源码分析HotSpot GC过程(二):DefNewGeneration的GC过程

    由于虚拟机的分代实现,虚拟机不会考虑各个内存代如何实现垃圾回收,具体的工作(对象内存的分配也是一样)由各内存代根据垃圾回收策略自行实现. DefNewGeneration的使用复制算法进行回收.复制算 ...

  6. GC是什么? 为什么要有GC?

    GC是什么? 为什么要有GC?  GC是垃圾收集器.  程序员不用担心内存管理,因为垃圾收集器会自动进行管理.要请求垃圾收集,可以调用下面的方法之一:  System.gc() Runtime.get ...

  7. 条款14:在资源管理类中心copying行为(Think carefully about copying behavior in resource-manage classes)

    NOTE: 1.复制RAII 对象必须一并赋值它所管理的资源,所以资源的copying行为决定RAII对象的copying行为. 2.普遍而常见的RAII class copying 行为是: 抑制c ...

  8. JVM--你常见的jvm 异常有哪些? 代码演示:StackOverflowError , utOfMemoryError: Java heap space , OutOfMemoryError: GC overhead limit exceeded, Direct buffer memory, Unable_to_create_new_native_Thread, Metaspace

    直接上代码: public class Test001 { public static void main(String[] args) { //java.lang.StackOverflowErro ...

  9. OutOfMemoryError: Java heap space和GC overhead limit exceeded在Ant的Build.xml中的通用解决方式

    这个仅仅是一点点经验,总结一下,当中前两个相应第一个Error.后两个相应第二个Error,假设heap space还不够.能够再改大些. <jvmarg value="-Xms512 ...

随机推荐

  1. [MST] Loading Data from the Server using lifecycle hook

    Let's stop hardcoding our initial state and fetch it from the server instead. In this lesson you wil ...

  2. hdu 1978 记忆化搜索

    注意: dp[i][j] 表示(i,j)这个点有多少种方式       mark[i][j]表示这个点是否走过  假设有直接返回dp[i][j]    dp的求法为全部梦走到点的dp的和 注意mark ...

  3. Linux之我最常用的20条命令

    Linux之我最常用的20条命令 玩过 Linux的人都会知道, Linux中的命令的确是非常多,但是玩过 Linux的人也从来不会因为 Linux的命令如此之多而烦恼,因为我们只需要掌握我们最常用的 ...

  4. Effective C++ 条款12

    复制对象时,勿忘其每个成分 作者在本节条款提醒我们,在多重继承的情况下进行copy或者copy assignment 的operator=的编写时,一定要考虑base 类部分数据的初始化后者复制. 对 ...

  5. Centos7+httpd+fastcgi+rails安装

    搭建的环境: centos7 Apache/2.4.6 fastcgi2.4.6 rails4 在安装fastcgi的时候遇到了问题: 问题: .... .. In file included fro ...

  6. SQLSever: 怎样在select中的每一行产生不同的随机数?

    select 的随机函数有点假, 或许是由于它是基于时间来的吧, 同一select中由于时间无法错开导致产生的随机数都是一样的. 怎样做到让不同的行拥有不同的随机数呢? 以下以产生某个月的随机日期来演 ...

  7. 使用iOS原生sqlite3框架对sqlite数据库进行操作

    摘要: iOS中sqlite3框架可以很好的对sqlite数据库进行支持,通过面向对象的封装,可以更易于开发者使用. 使用iOS原生sqlite3框架对sqlite数据库进行操作 一.引言 sqlit ...

  8. nyoj--46--最少乘法次数(数学+技巧)

    最少乘法次数 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 给你一个非零整数,让你求这个数的n次方,每次相乘的结果可以在后面使用,求至少需要多少次乘.如24:2*2=2 ...

  9. windows tensorflow 版本与升级

    tensorflow 的版本在 1.1.0/1.2.0 之后 api 迎来重大变化,有必要将版本升级到最新的 1.1.0 以上. 1. 使用 upgrade CPU:pip3 install –upg ...

  10. Most common words

    To find the most common words, we can apply the DSU pattern; most_common takes a histogram and retur ...