首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >GC算法-标记压缩算法

GC算法-标记压缩算法

作者头像
烟草的香味
发布于 2020-04-08 06:41:45
发布于 2020-04-08 06:41:45
1.1K00
代码可运行
举报
文章被收录于专栏:烟草的香味烟草的香味
运行总次数:0
代码可运行

概述

还记得标记清除复制算法的问题么? 堆使用效率低和碎片化问题. 那么有没有能够利用整个堆, 有没有内存碎片化问题的算法呢? 这就是标记压缩算法了.

简单来说, 标记压缩算法就是将堆中的所有活动对象整体向左移, 将对象间的空隙消除.

在GC执行前的内存:

GC执行后的内存:

恩, 就是这么个意思.

实现

如何实现上面的操作呢? 首先, 要将所有活动对象标记出来. 这是标记阶段, 跳过了, 跟标记清除一样操作就行. (这里每个对象都有一个mark属性, true为活动对象)

标记完了, 那就剩下压缩操作了. 如何进行呢?

  1. 遍历堆, 将所有活动对象挪到左边. 但是, 后面有对象引用了前边的对象, 你就找不到新的指针了, 因为那块地址很可能已经被覆盖了.
  2. ....

最后想了想, 还是得老老实实地三步走:

  1. 遍历堆, 将所有对象通过计算得到新的地址并保存
  2. 遍历堆, 将所有子对象的地址更新为新的地址, 同时更新根集合中的指针.
  3. 遍历堆, 将对象集体迁移. 指针的问题都解决了, 可以将对象搬到新家了.

步骤一: 计算所有对象的新地址

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// HEAP_START 是堆的开始位置, HEAP_END 是堆得结束位置
obj = HEAP_START
newAddr = HEAP_START
// 遍历所有活动对象
while(obj < HEAP_END){
    // 非活动对象, 跳过
    if(obj.mark != true){
        obj += obj.size;
        continue;
    }
    // 记录新的地址
    obj.newAddr = newAddr
    newAddr += obj.size
    // 继续遍历
    obj += obj.size
}

这遍完后, 所有活动对象都保存了自己的新地址, 然后就可以将所有指针的地址进行更新了.

步骤二: 更新所有指针

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 更新根集合中的指针
for(obj in roots){
    obj = obj.newAddr
}
/*
更新所有活动对象的指针
当然, 这里也可以修改为遍历所有活动对象, 并将指针进行更新. 但是会出现各种重复处理、指针覆盖等问题, 就直接遍历堆了.
*/
obj = HEAP_START
while(obj < HEAP_END){
    if(obj.mark != true){
        obj += obj.size;
        continue;
    }
    // 更新子对象
    for(child in children){
        child = child.newAddr
    }
    obj += obj.size
}

至此, 所有指针都已经更新完毕, 但是, 对象还没有移动. 只剩下最后一步了, 将对象按照步骤一的规律, 向左排排坐就好啦.

步骤三: 迁移对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
obj = newAddr = HEAP_START
while(obj < HEAP_END){
    if(obj.mark != true) {
        obj += obj.size;
        continue;
     }
    // 将obj的数据复制到newAddr处
    copyData(newAddr, obj, obj.size);
    // 清空数据, 为下一次GC做准本
    newAddr.mark = false;
    newAddr.newAddr = null;
    // 遍历下一个对象
    obj += obj.size
    newAddr += obj.size
}

至此, 实现基本完成. 创建对象分配内存的操作与复制算法一样. 这个算法简直是融合了标记清除复制算法的优点, 解决了他们的问题, 不光堆的使用效率变高了, 而且也没有内存碎片的问题了. 但是, 就是, 只不过要对堆进行三次遍历而已. 不过没关系啦, 毕竟有失才有得嘛. 不过是时间换空间了.

而这, 也是标记压缩算法最大的问题了, 执行时间太久了, 标记清除对堆进行一次遍历, 而标记压缩要进行三次. 三倍的时间. 可想而知.

不过也有伟人说了, 算法没有好不好, 只有是否适合. 这几种可达性的算法各有优劣吧.

标记压缩的衍生

Two-Finger算法

将堆的遍历次数减少到两次.

如上图所示, 在第一次遍历的时候, 指针1从前向后寻找空闲地址, 指针2从后向前寻找活动对象, 找到后在原地址中记录新地址, 并将对象进行复制.

第二次遍历就可以将所有对象中的指针进行更新了.

你也发现了, 这个算法如果不想发生内存碎片化, 那就只能令每个对象的空间都是相同的. 而事实上也确实是这样. 强行规定每个对象都占用相同大小的空间, 我不知道这算法有什么应用场景. (原谅我的无知)

其他

还有一些其他的表格算法lmmixGC算法等, 因为这两个我看的似懂非懂, 就不细说了.


标记压缩算法差不多就这么些. 告辞~~~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 烟草的香味 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
《垃圾回收的算法与实现》 一
                (1)头主要包括对象大小,对象种类和运行GC所需要的信息。
用户4415180
2022/06/23
9560
《垃圾回收的算法与实现》 一
GC算法-标记清除算法
寻找所有的活动对象, 要从一个起点开始, 根集合(包括栈、常量池等等), 然后一层一层找下去. 简单来说就像这样:
烟草的香味
2020/04/08
7500
垃圾回收算法|GC标记-清除算法
GC 标记-清除算法由标记阶段和清除阶段构成。在标记阶段会把所有的活动对象都做上标记,然后在清除阶段会把没有标记的对象,也就是非活动对象回收。
goodspeed
2020/12/22
1.3K0
垃圾回收算法|GC标记-清除算法
GC算法-复制算法
复制算法就是将内存空间二等分, 每次只使用其中一块. 当执行GC时, 将A部分的所有活动对象集体移到B中, 就可以将A全部释放.
烟草的香味
2020/04/08
7040
GC算法-复制算法
详解gc(垃圾回收)机制五:GC标记-压缩算法
gc标记-压缩算法是  详解gc(垃圾回收)机制三:GC复制算法  和  详解gc(垃圾回收)机制四:GC标记-清除算法    结合的产物
仙士可
2022/12/02
3780
【Android 内存优化】垃圾回收算法 ( 内存优化总结 | 常见的内存泄漏场景 | GC 算法 | 标记清除算法 | 复制算法 | 标记压缩算法 )
内存泄漏原理 : 长生命周期对象 , 持有短生命周期对象的引用 , 并且是强引用持有 , GC 无法释放该短生命周期对象引用 , 造成 OOM ;
韩曙亮
2023/03/27
1.5K0
【Android 内存优化】垃圾回收算法 ( 内存优化总结 | 常见的内存泄漏场景 | GC 算法 | 标记清除算法 | 复制算法 | 标记压缩算法 )
一文搞懂七种基本的GC垃圾回收算法
本文整理了七种常见 GC 算法的基本原理,包括 GC 标记-清除法、引用计数法、GC 标记-复制算法、GC 标记-压缩算法、保守式 GC、分代垃圾回收、增量式垃圾回收(三色标记法),可以作为学习 GC 知识的框架。
腾讯云开发者
2024/04/03
6.4K1
一文搞懂七种基本的GC垃圾回收算法
【愚公系列】2023年11月 大数据教学课程 011-JVM垃圾回收算法
C/C++语言是非常底层的语言,没有内置的垃圾回收机制,是通过new关键字申请内存资源,通过delete关键字释放内存资源。。这意味着程序员需要手动分配和释放内存,并负责管理程序的堆栈内存和堆内存。
愚公搬代码
2025/06/02
840
【愚公系列】2023年11月 大数据教学课程 011-JVM垃圾回收算法
几种常见GC算法介绍「建议收藏」
本文主要是对常用的GC算法(引用计数法、标记-清除法、复制算法、标记-清除算法)作出相关的说明,并对相关知识做简单的介绍。
全栈程序员站长
2022/07/04
3.2K0
几种常见GC算法介绍「建议收藏」
ZGC关键技术分析
垃圾回收对于Javaer来说是一个绕不开的话题,工作中涉及到的调优工作也经常围绕垃圾回收器展开。面对不同的业务场景没有一个统一的垃圾回收器能保证可GC性能。因此对程序员来说不仅要会编写业务代码,同时也要卷一下JVM底层原理和调优知识。这种局面可能因为ZGC的出现而发生改变,新一代回收器ZGC几乎不需要调优的情况下GC停顿时间可以降低到亚秒级。
得物技术
2023/10/19
5660
ZGC关键技术分析
jvm系列--GC
一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。
Dlimeng
2023/06/29
2210
jvm系列--GC
GC垃圾回收算法
「GC」是Garbage Collection的缩写,即回收垃圾,那么「垃圾」指的是什么呢?
Lvshen
2022/05/05
6680
GC垃圾回收算法
深入垃圾回收:理解GC的核心算法与实现
垃圾回收(Garbage Collection,GC)是现代编程语言中一项关键技术。它不仅解决了内存管理中的诸多问题,还为开发者提供了一个更高效、更安全的编程环境。本文将深入探讨GC的起源、主要算法以及这些算法在不同编程语言中的具体实现。
井九
2024/10/12
4080
深入垃圾回收:理解GC的核心算法与实现
GC
这篇文章主要概括的聊一聊GC,大概知道有哪些知识点或使用的时候需要注意什么。讲GC的文章一抓一大把,我就挑几个我个人比较有兴趣的地方分享一下。
JusterZhu
2023/09/18
3460
GC
Android GC 那点事
本文介绍了Dalvik和ART虚拟机在GC方面的区别,以及ART虚拟机在GC方面的新特性。
QQ空间开发团队
2016/10/25
4.2K0
Android GC 那点事
Android GC 原理探究
作者:陈昱全 知乎主页:https://www.zhihu.com/people/chen-yu-quan 前言 想写一篇关于android GC的想法来源于追查一个魅族手机图片滑动卡顿问题,由于不断的GC导致的丢帧卡顿的问题让我们想了很多方案去解决,所以就打算详细的看看内存分配和GC的原理,为什么会不断的GC,GC ALLOC和GC COCURRENT有什么区别,能不能想办法扩大堆内存减少GC的频次等等。 1、JVM内存回收机制 1.1 回收算法 标记回收算法(Mark and Sweep GC) 从”G
腾讯Bugly
2018/03/23
1.3K0
java进阶3:GC 的背景与一般原理
其最本质的原因是因为内存资源的稀缺性。我们计算机最核心的资源是CPU和内存,CPU是随着计算机一直存在的东西,核数有限但是一直存在;但内存比较稀缺,A占满了,B就不能用了,我们怎么可以共享使用这个内存呢,这就是GC产生的原因了。
你可以叫我老白
2023/07/05
3660
java进阶3:GC 的背景与一般原理
JVM 调优 2:GC 如何判断对象是否为垃圾,三色标记算法应用原理及存在的问题?
本文进入我们进入 JVM 调优系列 2,GC 如何判断对象是否为垃圾,这个是面试中的高频面试题,同时对于 GC 的三色标记算法属于 GC 算法的核心内容,我们将通过算法的应用原理进行深度剖析并分析存在的问题,由此来得出 GC 的制定机制是什么?这里就不再强调重点了,因为到处都是重点!
白鹿第一帅
2022/05/08
5990
JVM 调优 2:GC 如何判断对象是否为垃圾,三色标记算法应用原理及存在的问题?
JVM 调优系列 2:GC 如何判断对象是否为垃圾,三色标记算法应用原理及存在的问题
本文进入我们进入 JVM 调优系列 2,GC 如何判断对象是否为垃圾,这个是面试中的高频面试题,同时对于 GC 的三色标记算法属于 GC 算法的核心内容,我们将通过算法的应用原理进行深度剖析并分析存在的问题,由此来得出 GC 的制定机制是什么?这里就不再强调重点了,因为到处都是重点!
白鹿第一帅
2021/03/21
8390
JVM 调优系列 2:GC 如何判断对象是否为垃圾,三色标记算法应用原理及存在的问题
JVM内存与垃圾回收篇第15章垃圾回收相关算法
由于Root采用栈方式存放变量和指针,所以如果一个指针,它保存了堆内存里面的对象,但是自己又不存放在堆内存里面,那它就是一个Root。
yuanshuai
2022/08/17
2960
JVM内存与垃圾回收篇第15章垃圾回收相关算法
推荐阅读
相关推荐
《垃圾回收的算法与实现》 一
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档