java 垃圾回收机制以及经典垃圾回收器详解
作者:xiaoluo5238 发布时间:2022-07-06 05:16:08
判断对象存活方法
引用计数法:在对象中添加一个引用计数子,每当一个地方引用他时,计数器就加一,当引用失效时,计数器就减一。
会有对象循环引用问题:
objA.instance = objB
objB.instance = objA
objA 有objB 的引用 objB 有 objA 的引用,他们相互引用着对方。导致他们无法回收。
可达性分析:
从GC Roots 根对象作为起点,根据引用关系向下搜索,如果对象可达,就说明对象存活,如果对象不可达,就说明对象可以被回收。
GC Roots的根对象为:
1)在虚拟机栈 栈帧中的 本地变量表 中引用的对象
2)方法区静态属性引用的对象
3)方法区常量引用 的对象,如字符串常量池中的引用
4)本地方法栈中JNI引用的对象
5)虚拟机内部引用的对象,如基本数据类型对应的Class对象,一些常驻的异常对象等,还有系统类加载器
6)被同步锁持有的对象
等
收集线程和用户线程在并发可达性分析
并发 的可达性分析,由于用户线程会即时修改对象的引用关系, 可能会造成两种异常:
1)原本消亡的对象错误标记为存活,这个可以接受,就造成浮动垃圾,下一次收集即可。
2)原本存活的对象 标记为 消失。
三色法分析图:
黑色:已经扫描过的对象
灰色:已经访问过,但还有一个引用没有被扫描
白色:为被访问过,若到最后还是白色,说明此对象是需要回收的。
黑色误标记为白色有两个条件
1) * 插入一条或多条从黑色对象到白色对象的新引用
2) * 删除了全部从灰色对象到该白色对象的直接或间接的引用
解决方法:
1)增量更新,破坏条件1,把黑色对象对白色对象的新增引用记录下来,等并发扫描结束后,再以这些对象出发重新扫描。
2)原始快照(SATB),破解条件2,当灰色对象要删除对白色对象的引用关系时,记录下来。并发结束后再以记录节点开始重新扫描。
分代收集
堆:
新生代(1/3) 老年代(2/3)
新生代 分为 Eden/From/To
新生代存放:比较小,时长比较小
老年代:比较大 存放时长比较大
轻GC
重GC(full GC) -> STW(停止事件),fallGc特别费资源
Eden -> from <-> To -> old
对象在from和to循环15(默认)次之后,会放到老年代
垃圾收集算法
标记-清除 算法:
算法分为标记 和 清除两个阶段,首先标记出所需要回收的对象,标记完成之后,统一回收所标记的对象。
优点:最基础的算法,实现简单
缺点:1)执行效率不稳定,对象越多,效率越低
2)内存碎片化,需要分配大对象时可能无足够连续的空间。
代表垃圾收集器:
标记复制算法(复制算法):
把内存分为大小相等的两块,每次只使用其中一款,当一块快用完时,它将存活的对象复制到另一块上。
优点:能产生连续的空间
缺点:耗内存,对象存活率较高时,效率会降低(不适合老年代)。
代表垃圾收集器: 很多新生代的回收,都用这种算法。
标记整理 算法
首先标记出所需要的对象,标记完成后,对存活对象移动到内存的一段,然后清除边界外的对象。
优点:有连续的内存空间;系统吞吐量(用户线程和收集器的效率总和)会提高。
缺点:整理内存耗时会比较大,会造成 “Stop The World”;
代表垃圾收集器:Parallel Scavenge收集器
CMS中主要用标记清除算法,但是当内存碎片化到影响对象分配时,就会使用一次标记整理算法 去整理内存碎片。
垃圾收集器
Serial收集器
最基础最悠久的垃圾收集器,叫做 串行收集器,它进行垃圾收集的时候,会停止用户线程(Stop the world)。
新生代垃圾收集器用 Serial,基于复制算法
老年代垃圾收集器用 Serial Old,基于标记整理算法。
优点:所有垃圾收集器中内存消耗最小的,对单核或单线程处理器来说,效率很高。运行在客户端
缺点:stop the world
ParNew收集器
ParNew收集器就是Serial收集器的多线程并行版,除了支持多线并行收集之外,没有太多创新之处。
CMS垃圾收集器作为老年代垃圾收集器,不能与Parallel Scavenge配合工作,只能选择 ParNew或者Serial收集器。
Parallel Scavenge收集器
新生代垃圾收集器,基于 标记复制算法,也是可以通过并行收集的多线程收集器。他关注 吞吐量(用户线程时间/总时间)。
CMS 垃圾收集器
CMS 收集器是一种以获取最短停顿时间作为目标的垃圾收集器。基于标记清除算法。
步骤:
初始标记->并发标记->重新标记->并发清除
1)初始标记:stop the world,标记GC ROOT 能直接关联的对象,速度很快
2)并发标记:从GC Root直接关联的对象开始遍历整个对象图,时间较长,但与用户线程并行
3)重新标记:stop the world,修正并发标记期间对象的状态的改变(增量更新算法,标记新的黑色指向白色的引用),时间也比较短。
4)并发清除:与用户线程同步。
优点:并发收集、低停顿。
缺点:
1)对处理器资源敏感,当处理器核心数量在四个以下时,CMS对用户程序影响很大。
2)有浮动垃圾,并发标记时会产生新的垃圾,但是CMS本次不会清理它,要等到下一次才会清理。从而可能造成内存不够而产生Stop the world 的Full GC
3)基于标记清除算法,会产生大量的空间碎片,而触发Full GC
G1垃圾收集器
关注吞吐量和延迟时间的最佳平衡。
从整体看,主要采用标记整理算法,从局部看,是标记-复制算法(两个Region 之间的复制)。
G1把 java对 划分为多个大小相等独立区域 Region,每一个Region 都可以根据需要,扮演 Eden空间、Survivor空间或者老年代空间。
G1对年代的划分存在概念上,它可以不是连续的区间。。
Region 还有一类特殊的Humongous区域,专门存储大对象(1M-32M,可配),把超过Region大小的对象分配在连续的 Humongous Region之中。
每次收集时以Region作为最小单元,G1收集器去根据Region里面垃圾队的价值大小,在后台维护一个优先级列表,优先处理回收价值收益最大的那些Region(每次收集到的内存大小及回收时间的经验值)。
G1至少耗费打印java堆容量的10%到20%来维持收集工作。
TAMS指针:在并发过程中保存新建的对象。
STAB:灰色引用对白色引用的删除 记录下来。
G1的步骤:
1)初始标记:stop the world,仅仅标记GC ROOTs 能直接关联的对象,并且修改TAMS指针
2)并发标记:从GC ROOTS 直接关联的对象出发,扫描对象图(并还要处理SATB记录下并时有变动的对象),时间长,但是与用户线程并行,
3)最终标记:stop the world,短暂,处理遗留下来的少量SATB记录
4)帅选回收:stop the world,负责更新Region的统计数据,对Region的回收价值和成本进行排序。根据用户所期望的停顿时间(JVM参数可配)来制定回收计划。可以自由选择多个Region作为回收集,然后把存活的对象复制到空的Region中,然后清空回收集的Region。
除了并发标记外,其它都用停止用户线程,目标不是单纯的追求低延迟,而是延迟可控的情况下获取最大的吞吐量(用户线程时间/总时间,总时间为用户线程时间+垃圾收集时间)。
来源:https://blog.csdn.net/xiaoluo5238/article/details/115329940


猜你喜欢
- 哎,最近很好久没写点东西了,由于工作的原因,接触公司自己研发的底层orm框架,偶然发现该框架在调用jdbc操作的时候参考的是hibernat
- 一、@RequestMapping注解的功能从注解名称上我们可以看到,@RequestMapping注解的作用就是将请求和处理请求的控制器方
- 如图,刚开始报错获取不到bean因为配置文件1、原因一: *.properties等没有值,还是用${变量的}。获取不到,于是把所有值复制到
- 本文介绍了Android TextView属性ellipsize多行失效的解决思路,分享给大家,具体如下:多余文字显示省略号的常规做法and
- 队列简介队列是一个有序列表,可以用数组或是链表来实现。遵循先入先出的原则。即先存入队列的数据,先取出,后存入的后取出。示意图:(使用数组模拟
- 前言:在 Java 语言中,并发编程都是依靠线程池完成的,而线程池的创建方式又有很多,但从大的分类来说,线程池的创建总共分为两大类:手动方式
- 前言J.U.C是java包java.util.concurrent的简写,中文简称并发包,是jdk1.5新增用来编写并发相关的基础api。j
- 本文实例讲述了Android简单获取经纬度的方法。分享给大家供大家参考,具体如下:public void getLoc() {
- 本文实例为大家分享了ActionBar下拉式导航的实现代码,供大家参考,具体内容如下利用Actionbar同样可以很轻松的实现下拉式的导航方
- 知识点:内部存储空间获取总大小和可用大小;sdcard存储空间获取总大小和可用大小;新名词记录{StatFs:描述文件系统信息的类}概览在开
- 概述java.util.Random可以产生int、long、float、double以及Goussian等类型的随机数。这也是它与java
- 比如在类上使用该注解 @Alias("dDebtEntity")则在mapper.xml文件中resultType=&q
- 偶然间发现了Android.inputmethodservice.Keyboard类,即android可以自定义键盘类,做了一个简单例子供大
- 目录规则(来自百度百科,康威生命游戏词条)控制台实现的关键接口代码实现规则(来自百度百科,康威生命游戏词条)游戏开始时,每个细胞随机地设定为
- SpringBoot2底层注解一、@ImportResource@Conditional注解,是根据条件进行装配。满足了 Condition
- 本文实例为大家分享了C#窗体实现酒店管理系统的具体代码,供大家参考,具体内容如下一、概述酒店管理系统是我们常说的MIS (Managemen
- java 单例的五种实现方式及其性能分析序言在23种设计模式中,单例是最简单的设计模式,但是也是很常用的设计模式。从单例的五种实现方式中我们
- 这是一个可以从乱码文本中得到正确的原始文本的程序,其基于的原理在于错误的编码往往导致位补充,因此正确的文本使用的字节数应该是最少的(之一)。
- using System;using System.Collections.Generic;public class Example{ &n
- 一、简介(1)、MySQL是一个关系型数据库系统,是如今互联网公司最常用的数据库和最广泛的数据库。为服务端数据库,能承受高并发的访问量。(2