Java GC(Garbage Collector)标记-清除算法:

1、标记清除算法: 点击了解:Java的内存管理
GC标记-清除算法由标记阶段和清除阶段构成,在标记阶段会把所有的活动对象都做上标记,然后在清除阶段会把没有标记的对象,也就是非活动对象回收。
名词解释:
对象:在GC的世界里对象指的是通过应用程序利用的数据集合,是GC的基本单位。一般由头(header)和域(field)构成。
活动对象:能通过引用程序引用的对象就称为活动对象。(可以直接或间接从全局变量空间中引出的对象)
非活动对象:不能通过程序引用的对象被称为非活动对象。(这就是被清除的目标)
标记清除的伪代码如下:

func mark_sweep{mark_phase();    //标记阶段sweep_phase();    //清除阶段
}

2、:标记阶段:
标记阶段就是遍历对象并标记的处理过程。
标记阶段的伪代码如下:

func mark_phase(){for( r : $roots)   //在标记阶段,会给所有的活动对象打上标记mark(*r)
}
func mark(){if(obj.mark == False)obj.mark = True     //先标记找出活动对象for(child : children(obj))   //然后递归的标记通过指针数据能访问到的对象mark(*child)
}

这里$root是指针对象的起点,通过$root可以遍历全部活动对象。

下面是标记前标记后内存中堆的状态:


3、:清除阶段:
在清除阶段,collector会遍历整个堆,回收没有打上标记的对象(垃圾),使(堆)其能再次利用。
sweep_phase()函数伪代码实现如下:

func sweep_phase(){sweeping = $heap_start   //首先将首地址赋值给sweepingwhile(sweeping < $head_end){if(sweeping.mark == True)//如果是标记状态就设为False,如果是活动对象,还会在标记阶段被标记为TRUEsweeping.mark == FALSEelse:sweeping.next = $free_list    //将非活动对象 拼接到$free_list 头部位置$free_list = sweepingsweeping += sweeping.size}
}

注:
size域指的是存储对象大小的域,在对象头中事先定义。
next域只在生成空闲链表中取出分块时才会用到。
分块(chunk)这里是指为 利用对象而事先准备出来的空间。
内存中区块的块生路线为 分块--> 活动对象 --> 垃圾 --> 分块 --> ...

在清除阶段我们会把非活动回收再利用。回收对象就是把对象作为分块,连接到被称为空闲链表的单向链表。之后再分配空间时只需遍历这个空闲链表就可以找到分块了。

下图是清除阶段结束后堆的状态:

4、分配:
回收垃圾的目的是为了能再次分配。

当程序申请分块时,怎样才能把大小合适的分块分配给程序呢?
分配伪代码如下:

func new_obj(size){chunk = pickup_chunk(size,$free_list)    //遍历$free_list寻找大于等于size的分块if(chunk != null)return chunkelseallocation_fail() //如果没找到大小合适的分块 提示分配失败
}

pickup_chunk()函数不止返回和size大小相同的分块,也会返回大于size大小的分块(这时会将其分割成size大小的分块和去掉size后剩余大小的分块,并把剩余部分还给空闲链表)。
分配有三种策略:
First-fit:发现大于等于size的分块立刻返回
Best-fit:找到大小和size相等 的分块再返回
Worst-fit:找到最大的分块,然后分割成size大小和剩余大小(这种方法容易产生大量小的块)

5、合并:
根据分配策略的不同,分配过程中会出现大量小的分块,如果分块是连续的,我们就可以把小分块合并生成一个大的分块,合并是在清除阶段完成的,包含了合并策略的清除代码如下:

func sweep_phase(){sweeping = $heap_start            // 首先将堆的首地址赋值给 sweepingwhile(sweeping < $head_end){if(sweeping.mark == TRUE)// 如果是标记状态就设为 FALSE,如果是活动对象,还会在标记阶段被标记为 TRUEsweeping.mark == FALSE    else:if(sweeping == $free_list + $free_list.size)  // 堆的地址正好和空闲链表大小相同$free_list.size += sweeping.sizeelsesweeping.next = $free_list   // 将非活动对象 拼接到 $free_list 头部位置$free_list = sweepingsweeping += sweeping.size}
}

$heap_end = $heap_start + HEAP_SIZE
所以这里sweeping == $free_list + $free_list.size可以理解为需要清除的堆的地址正好和空闲链接相邻

6、优缺点:
优点:
a、实现简单。
b、与保守式GC算法兼容。
缺点:
a、碎片化严重(由上面描述的分配算法克制,容易产生大量小的分块)
b、分配速度慢(由于空闲区块是用链表实现,分块可能是不连续的,每次分配都需要遍历空闲链表, 极端情况是需要遍历整个链表的)。
c、与写时复制技术不兼容

写时复制(copy-on-write)是众多UNIX操作系统用到的内存优化方法,比如在linux系统中使用fork()函数复制进程时,大部分内存空间都不会被复制,只是复制进程,只有在内存中内容被改变时才会被复制内存数据,但是如果使用标记清除算法,这时内存会被设置标志位,就会频繁发生不应该发生的复制。

多个空闲链表:
上面所说的标记清除算法只用到了一个空闲链表对大小不一的分块统一处理,但这样做每次都需要遍历一遍来寻找大小合适的分块,非常浪费时间。
这里我们使用多个空闲链表的方法来储存活动对象。比如:将两个字的分块组成一个空闲链表,三个字的分块组成另一块空闲链表,等等。。。
这时,如果我们需要分配三个字的分块,那我们值需要查询对应的三个字的空闲链表就可以了。

到底需要制造多小个空闲链表呢?
因为通常程序不会申请特别大的分块,所以我们通常给分块设置一个上限,比如100大于这个上限的组成一个特殊的空闲链表。这样101个空闲链表就够了。

位图标记:
在单纯的GC标记-清除算法中,用于标记的位置是被分配到对象头中去的,算法是把对象和头一并处理,但这个写时复制不兼容。
位图标记法是只收集各个对象的标志位并表格化,不和对象一起管理,在标记的时候不在对象的头里设置位置,而是在特定的表格中置位。

位图标记中重要的是,位图表格中位的位置要和堆里的各个对象切实对应,一般来说堆中的一个字会分配到一个位。

位图标记中mark()函数的伪代码实现如下:

func mark(obj){obj_num = (obj - $heap_start) / WORD_LENGTH  // WORD_LENGTH 是一个常量,表示机器中一个字的位宽index = obj_num / WORD_LENGTHoffset = obj_num % WORD_LENGTHif ($bitmap_tbl[index] & (1 << offset)) == 0$bitmap_tbl[index] |= (1 << offset)for (child: children(obj)) // 然后递归的标记通过指针数组能访问到的对象mark(*child)
}

这里 obj_num 指的是从位图表格前面数,obj 的标志位在第几个。例如 E 的 obj_num 是8。
obj_num 除以 WORD_LENGTH 得到的商 index 以及余数 offset 来分别表示位图表格的行编号和列编号。
优点:
a、和写时复制技术兼容
b、清除更高效(只需要遍历位图表格就可以,清除的时候也只需要清除表格中的标志位)。

延迟清除:
清除操作所花费的时间和堆的大小成正比,堆越大,标记-清除 动作花费的时间越长,也就越影响程序的运行。

延迟清除(lazy sweep)是缩短清除操作花费导致程序最大暂停时间的方法。

最大暂停时间,因执行 GC 而暂停执行程序的最长时间。

延迟清除中 new_obj() 函数会在分配的时候调用 lazy_sweep()函数,进行清除操作。如果它能用清除操作来分配分块,就会返回分块,如果不能分配分块,就会执行标记操作。然后重复这个步骤,直到找到分块或者allocation_fail

通过延迟清除法可以缩减程序的暂停时间,不过延迟效果并不是均衡的。
比如下图这种刚标记完堆的情况:

这时,活动对象和非活动对象都是相邻分布,如果程序在活动对象周围开始清除,那它找到的对象都是活动对象不可清除,只能不停遍历,暂停时间就会变长。

Java GC的标记-清除算法【总结】相关推荐

  1. java标志清理_JVM内存管理之GC算法精解(五分钟让你彻底明白标记/清除算法)...

    相信不少猿友看到标题就认为LZ是标题党了,不过既然您已经被LZ忽悠进来了,那就好好的享受一顿算法大餐吧.不过LZ丑话说前面哦,这篇文章应该能让各位彻底理解标记/清除算法,不过倘若各位猿友不能在五分钟内 ...

  2. 26 Java GC算法 垃圾收集器、标记 -清除算法、复制算法、标记-压缩算法、分代收集算法

    26.Java GC算法 垃圾收集器 1.1.1标记 -清除算法 1.1.2复制算法 1.1.3标记-压缩算法 1.1.4分代收集算法 26.Java GC算法 垃圾收集器 概述 垃圾收集 Garba ...

  3. 【Android 内存优化】垃圾回收算法 ( 内存优化总结 | 常见的内存泄漏场景 | GC 算法 | 标记清除算法 | 复制算法 | 标记压缩算法 )

    文章目录 一. 内存优化总结 二. 常见的内存泄漏场景 三. 内存回收算法 四. 标记-清除算法 ( mark-sweep ) 五. 复制算法 六. 标记-压缩算法 一. 内存优化总结 内存泄漏原理 ...

  4. JVM内存管理–GC算法精解(五分钟让你彻底明白标记/清除算法)

    相信不少猿友看到标题就认为LZ是标题党了,不过既然您已经被LZ忽悠进来了,那就好好的享受一顿算法大餐吧.不过LZ丑话说前面哦,这篇文章应该能让各位彻底理解标记/清除算法,不过倘若各位猿友不能在五分钟内 ...

  5. 67.Java垃圾收集机制\对象引用\垃圾对象的判定\垃圾收集算法\标记—清除算法\标记—整理算法\分代收集\垃圾收集器\性能调优

    67.Java垃圾收集机制 67.1.对象引用 67.2.垃圾对象的判定 67.3.垃圾收集算法 67.3.1.标记-清除算法 67.3.2.标记-整理算法 67.3.3.分代收集 67.4.垃圾收集 ...

  6. JVM内存管理------GC算法精解(五分钟让你彻底明白标记/清除算法)

    转载自  JVM内存管理------GC算法精解(五分钟让你彻底明白标记/清除算法) 相信不少猿友看到标题就认为LZ是标题党了,不过既然您已经被LZ忽悠进来了,那就好好的享受一顿算法大餐吧.不过LZ丑 ...

  7. 垃圾回收算法与实现系列-GC 标记-清除算法

    导语   在GC 中最重要的算法就是GC标记-清除算法(Mark-Sweep GC).在很多的场景下都还是在使用这个算法来进行垃圾回收操作.就如如同它的名字一样先标记,然后清除.下面就来看看标记清除算 ...

  8. 垃圾回收算法|GC标记-清除算法

    本文是<垃圾回收的算法与实现>读书笔记 什么是GC标记-清除算法(Mark Sweep GC) GC 标记-清除算法由标记阶段和清除阶段构成.在标记阶段会把所有的活动对象都做上标记,然后在 ...

  9. 【Java 虚拟机原理】垃圾回收算法 ( 标记-清除算法 | 复制算法 | 标记-整理算法 )

    文章目录 总结 一.标记-清除算法 二.复制算法 三.标记-整理算法 总结 常用的垃圾回收算法 : 标记-清除算法 ; 复制算法 ; 标记-整理算法 ; 这些算法没有好坏优劣之分 , 都有各自的 优势 ...

最新文章

  1. 剑指offer 25: 二叉树中和为某一值的路径
  2. IOS之学习笔记四(类的实现和对象和id)
  3. Redis:02---安装Redis(Linux+Windows+Docker)
  4. BZOJ-1951 古代猪文 (组合数取模Lucas+中国剩余定理+拓展欧几里得+快速幂)...
  5. 推荐两个在线格式化JavaScript代码的网站
  6. UILabel「行距,首行缩进」
  7. hashcode值一样对象一定相同吗_硬核问题,为什么重写equals()就要重写hashCode()?
  8. nginx https透明代理_五分钟看懂 Nginx 负载均衡
  9. 今年阿里巴巴重要开源项目全在这里
  10. svn提示Node remains in conflict的解决办法
  11. 海马汽车经销商管理系统技术解析(四)保养管理
  12. whois php,域名whois php
  13. Keras实现小数量集图片分类——6类别Birds数据集分类
  14. kaldi教程_赠书 | 全球稀缺的Kaldi学习资料,《Kaldi语音识别实战》给补上了
  15. 头条抖音后端技术3面,2021Java通用流行框架大全,含面试题+答案
  16. 运维实操——日志分析系统ELK(中)之logstash采集数据、伪装rsyslog、多行过滤、grok切片
  17. 关于OPENSSL的EVP函数的使用
  18. 用博奥如何导入单项工程电子表_博奥使用说明
  19. 时间服务器ntp配置文档,NTP 及时区配置
  20. 天之痕java版与ios版_iOS 获取当前app的名称和版本号

热门文章

  1. 【转载】Pyramid的权限管理
  2. 实验二——网络嗅探与欺骗.
  3. 2021-05-18 C#.NET面试题 Session有什么重大BUG,微软提出了什么方法加以解决?
  4. YOLOv5改进之十七:CNN+Transformer——融合Bottleneck Transformers
  5. Java代码评审歪诗!让你写出更加优秀的代码!
  6. GIT客户端32位安装版Git-2.34.0-32-bit.exe
  7. Burp Suite测试小程序,设置代理之后手机一直连不上网
  8. 咖啡在手,指数我有——指数咖啡
  9. linux xunsou_Linux 之 xunsearch
  10. jenkins创建流水线,基于gitlab与Jenkinsfile