GC算法-复制算法

概述

复制算法就是将内存空间二等分, 每次只使用其中一块. 当执行GC时, 讲A部分的所有活动对象集体移到B中, 就可以讲A全部释放.

画个图就是:

? 在执行GC前, 内存长这样:

? 当执行GC后, 内存就变成这样了:

还记得标记清除算法的问题是什么吗? 内存碎片化严重. 现在好了, 碎片化问题解决了, 每次GC执行后, 内存空间都是连续的啦.

实现

想一想GC执行的步骤是什么? 很简单啊, 遍历所有可访问的对象, 将所有对象的复制到另一块内存中. 完毕.

遍历所有根集合的对象, 跳过. 将每个对象都调用一次copy函数, 那么, 这个copy函数如何实现呢?

function copy(obj){
    // 若对象已经被复制过了, 则将其直接返回
    if(obj.isCopy == true){
        // 在原来对象中保存一下新的地址, 方便返回
        return obj.newAddr;
    }
    // 这里假设有一个全局变量 ADDR 指向空闲内存的首地址
    // 这里直接将 obj的size大小复制到ADDR的地方
    copy_data(ADDR, obj, obj.size);
    // 记录复制
    obj.isCopy = true;
    obj.newAddr = ADDR;
    // 更新空闲地址
    ADDR += size;
    // 将所有子对象复制
    for(child in children){
        child = copy(child);
    }
    return obj.newAddr;
}

将所有根集合中的对象依次调用copy函数, 完成复制.

复制算法分配新的对象变简单了, 有没有? 因为地址都是连续的, 所以申请新的地址也不用遍历链表等一堆操作, 直接按着地址划分空间就行了.

分析

很明显, 复制算法解决了标记清除的一个大问题, 内存碎片化严重. 在这里, 根本不存在碎片化问题的好嘛. 其相比标记清除的优势还是有一些的:

  1. 内存不会发生碎片化
  2. 最大暂停时间更短: 复制算法只需要遍历所有的活动对象, 而不需要遍历堆, 比标记清除要少一个堆的遍历, 故而执行更快.
  3. 内存分配高效: 标记清除是怎么分配内存的? 通过一个空闲地址的链表, 然后挨个找. 而复制算法将所有可分配的内存都放到一起了, 直接切割即可.
  4. 更好的局部访问: 复制算法复制后将对象与子对象放到一起, 这样缓存在读取的时候就能够一起读取, 防止多次读取数据.

当然, 缺点也很明显. 将堆一分为二, 使用效率急速下滑.

  1. 堆的使用效率低, 只有1/2
  2. 频繁的递归调用函数. 对栈的压力比较大, 但是我们都知道, 所有用递归能写的都可以换成循环来实现, 所以个人感觉这个并不是问题.

我看到有一种多空间复制算法, 为了提高堆的使用效率. 将堆空间分成N份, 其中的两份使用复制算法, 剩余的使用其他方法执行GC. 我实在是没有明白这么做的好处在哪....

原文地址:https://www.cnblogs.com/hujingnb/p/12642079.html

时间: 2024-10-08 10:41:42

GC算法-复制算法的相关文章

JVM-内存回收算法--复制算法

复制算法,它将堆上的内存分为两个大小相等的区域,一个是空闲区域,一个是活动区域.在程序运行中,实际使用的是活动区域,也就是有50%的空间被浪费掉. 复制算法的实现过程:1.找出活动空间中所有存活的对象.2.将这些存活的对象复制到空闲区域.3.将之前的活动空间清空,然后,就变为空闲空间了,而存活对象所在的区域,则变为活动空间了. 复制算法的优点,就是,内存回收完毕后,有一大片连续的可用空间.缺点,当然是,在程序运行期间,有50%的内存空间被放着,只有在发生内存回收的时候,GC才会借用空闲区域来实现

GC: 垃圾回收算法

标记-清除算法标记-清除(Mark-Sweep)算法是最基础的算法,就如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象.之所以说它是最基础的收集算法,是因为后续的收集算法都是基于这种思路并对其缺点进行改进而得到的.它主要有两个缺点:一个是效率问题,标记和清除过程的效率都不高:另外一个是空间问题,标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致,当程序在以后的运行过程中需要分配较大对象时无法找到足够连续的内存空间而

《垃圾回收的算法与实现》——GC复制算法

https://www.cnblogs.com/suolu/p/6654236.html 基本概念 GC复制算法将堆分成From和To两个内存块,当From被占满时GC将From中的存活对象复制到To中,同时将From和To交换. 通过递归遍历GC root(即采用深度优先)复制存活对象,对于已经复制过的标记其COPIED字段. 复制过的对象将在From的对象的forwarding记录To中该对象地址,以便于其余引用了该对象的引用进行修改. 分配对象时将先判断From中连续可用空间是否够用(复制

Java GC 垃圾回收算法 内存分配

垃圾回收(Garbage Collection, GC)是Java不同于c与c++的重要特性之一. 他帮助Java自动清空堆中不再使用的对象. 由于不需要手动释放内存,程序员在编程中也可以减少犯错的机会. 利用垃圾回收,程序员可以避免一些指针和内存泄露相关的bug(这一类bug通常很隐蔽). 垃圾回收实际上是将原本属于程序员的责任转移给计算机. GC需要完成的3件事情: 哪些内存需要回收 什么时候回收 如何回收 1 回收那些对象? 在Java中采用可达性分析算法来判定对象是否存活,是否可以被回收

GC原理---垃圾收集算法

垃圾收集算法 Mark-Sweep(标记-清除算法) 标记清除算法分为两个阶段,标记阶段和清除阶段.标记阶段任务是标记出所有需要回收的对象,清除阶段就是清除被标记对象的空间. 优缺点:实现简单,容易产生内存碎片.因为会存在大量的空间碎片,因为回收后的空间是不连续的,这样给大对象分配内存的时候可能会提前触发full gc. 标记-压缩算法 首先也需要从根节点开始对所有可达对象做一次标记,但之后,它并不简单地清理未标记的对象,而是将所有的存活对象压缩到内存的一端.之后,清理边界外所有的空间.这种方法

复制算法

复制算法:如果jvm使用了coping算法,一开始就会将可用内存分为两块,from域和to域, 每次只是使用from域,to域则空闲着.当from域内存不够了,开始执行GC操作,这个时候,会把from域存活的对象拷贝到to域,然后直接把from域进行内存清理. 优点:在存活对象不多的情况下,性能高,能解决内存碎片和java垃圾回收算法之-标记清除 中导致的引用更新问题.缺点: 会造成一部分的内存浪费. coping算法一般是使用在新生代中,因为新生代中的对象一般都是朝生夕死的,存活对象的数量并不

【啊哈!算法】算法7:Dijkstra最短路算法

上周我们介绍了神奇的只有五行的Floyd最短路算法,它可以方便的求得任意两点的最短路径,这称为“多源最短路”.本周来来介绍指定一个点(源点)到其余各个顶点的最短路径,也叫做“单源最短路径”.例如求下图中的1号顶点到2.3.4.5.6号顶点的最短路径. <ignore_js_op> 与Floyd-Warshall算法一样这里仍然使用二维数组e来存储顶点之间边的关系,初始值如下. <ignore_js_op> 我们还需要用一个一维数组dis来存储1号顶点到其余各个顶点的初始路程,如下.

【啊哈!算法】算法6:只有五行的Floyd最短路算法

暑假,小哼准备去一些城市旅游.有些城市之间有公路,有些城市之间则没有,如下图.为了节省经费以及方便计划旅程,小哼希望在出发之前知道任意两个城市之前的最短路程. 上图中有4个城市8条公路,公路上的数字表示这条公路的长短.请注意这些公路是单向的.我们现在需要求任意两个城市之间的最短路程,也就是求任意两个点之间的最短路径.这个问题这也被称为“多源最短路径”问题. 现在需要一个数据结构来存储图的信息,我们仍然可以用一个4*4的矩阵(二维数组e)来存储.比如1号城市到2号城市的路程为2,则设e[1][2]

Dijkstra算法——《算法导论》学习心得(十三)

这两天在做一个项目,关于北京市出租车的,然后用到了Dijkstra算法,所以这篇文章就先写Dijkstra算法了.在大二下的时候学了数据结构,书里面也讲了Dijkstra算法,但是当时怎么也没理解,结果考试的时候就考了,哎蛋疼!现在用到了,又得硬着头皮去学,结果很快弄明白了,只是在写代码时出了一些很低级的错误,调Bug用了不少时间.最后总结只能说:不是你不会,而是没到你非会不可的地步!在这篇文章里我就用实际的项目给大家讲Dijkstra算法. 背景: 迪杰斯特拉算法是由荷兰计算机科学家狄克斯特拉