JVM——Gabage Collection_精华总结_一篇文章看完GC垃圾收集机制

判断是不是垃圾

首先我们需要判断这些对象是不是垃圾

引用计数算法

有地方引用他,计数器加一

引用失效,计数器减一

计数器为零时,不可再被使用,等待被回收

优点:原理简单,判定效率高,

缺点:两个对象互相引用,永远无法回收

可达性分析算法

Roots根对象,根据引用关系向下搜索

谁能成为Roots:

1:在栈帧中的本地变量表中引用的对象,比如:方法中的参数、局部变量、临时变量

2:类静态属性引用的对象

3:常量引用的对象,比如字符串常量池里的引用:new String("abc").intern()

4:本地方法栈中JNI引用的对象

5:被同步锁持有的对象

6:虚拟机内部的引用,基本数据类型对应的Classs对象

与引用的类型有关

强引用:赋值,new关键字创建对象,不会被回收

软引用:发生内存溢出前,二次回收,释放内存,适合实现缓存

弱引用:必被回收

虚引用:无法创建对象实例,只是为了在某个对象被回收时得到一个系统通知

死前还有一次机会

finalize()方法

只执行一次

把自己(使用this关键字)赋值给某个类变量或者对象的成员变量,与引用链上的对象重新建立关联,被引用链上的对象引用

但不建议用这个方法,运行代价高,不确定性大,无法保证各个对象的调用顺序

方法区

让我们看看方法区里有哪些会被回收

废弃的常量

没有任何字符串对象引用常量池中的常量

没有任何地方与常量池中的类、方法、字段有符号引用

不再使用的类型

三个条件:

1:该类在java堆中的所有实例都已经被回收

2:加载该类的类加载器都已经被回收

3:该类对应的java.lang.Class对象没有在任何地方被引用,没有在任何地方通过反射访问该类的方法

满足条件也不一定就回收,可以用参数控制

收集的方式(追踪式垃圾收集)

垃圾收集有哪些收集方式呢

垃圾收集的算法

标记-清除算法

标记死的活的都可以,干掉死的

缺点:

执行效率不稳定、内存空间碎片化

收集器:关注延迟的CMS收集器

标记-复制算法

可用内存按容量划分大小相等的两块

一半的内存用完了,将存活着的对象复制到另一块上

缺点:浪费内存空间

实际应用:新生代分为一块较大的Eden空间和两块较小的Survivor空间,每次只用Eden和一块Survivor空间,新生代大部分是死的快的对象,所以基本够用

如果不够用,进行分配担保,把多的存活对象放在老年代里

标记-整理算法

让所有存活的对象都向内存空间一端移动,然后直接清理掉边界以外的内存

这种对象移动操作要全程暂停用户应用程序,Stop The World

收集器:关注吞吐量的Paralled Old收集器

基于分代收集理论

新生代的对象:朝生夕灭,每次回收都有大批对象死去

老年代的对象:难以消亡,回收的频率可以低一些,减少垃圾收集整体时间

跨代引用问题

老年代会引用新生代的对象

假说:跨代引用相对于同代引用来说仅占极少数

推论:存在互相引用关系的两个对象,是应该倾向于同时生存或者同时消亡的

解决方式:新生代上建立记忆集,记忆集把老年代分割成一小块一小块,标识出哪一块存在跨代引用,存在跨代引用的那一块内存里的对象才被加入GC Roots进行扫描

PS:目前只有CMS收集器会有单独收集老年代的行为

经典垃圾收集器

衡量垃圾收集器的三项指标:

内存占用、吞吐量、延迟

书中关于新生代和老年大垃圾收集器的搭配图:

Serial收集器

最基础,单线程工作,HotSpot虚拟机运行在客户端模式下的默认新生代收集器,简单高效,额外内存消耗小

新生代采取标记-复制,老年代采用标记-整理

适用于单CPU、新生代空间较小和对暂停时间要求不是很高的应用上

ParNew收集器

Serial收集器的多线程版本

除了Serial,只有它能和CMS收集器(收集老年代)配合工作,基本是并入CMS,成为它处理新生代的组成部分

PS收集器没有CMS并发进行时发生MinorGC需要的相应处理,所以不行

Paralled Scavenge收集器

新生代收集器

基于标记-复制

关注吞吐量,提供两个参数精确控制吞吐量:最大垃圾收集停顿时间、设置吞吐量大小

不根据-XX:PretenureSizeThreshold决定对象是否在旧生代上直接分配,eden区不够时,如果大于等于eden区一半的大小,就直接在旧生代上分配

PS:垃圾收集停顿时间缩短是以牺牲吞吐量和新生代空间为代价换取的:缩小新生代的内存空间,收集的停顿时间少了,但是频率就要高,在一段时间内用于收集的总时间就会变长

Serial Old收集器

Serial收集器的老年代版本,使用标记-整理算法,供客户端下的HotSpot虚拟机使用

应用:JDK5以及之前的版本与Paralled Scavenge收集器搭配使用

作为CMS收集器失败时的备胎

Paralled Old收集器

基于标记-整理

Parallel Scavenge加Parallel Old收集器组合,注重吞吐量

CMS收集器

以获取最短回收停顿时间为目标的收集器,关注服务的响应速度

基于标记-清除算法,分为四个步骤:

1:初始标记:需要STW,标记直接被Roots引用的对象

2:并发标记:遍历整个对象图,耗时长,但是不需要停顿

3:重新标记:并发标记期间,可能标记会改变

4:并发清除

缺点:

占用资源,降低总吞吐量

无法及时处理并发时产生的浮动垃圾

空间碎片(设置参数,若干次不整理空间的Full GC后 下一次Full GC前整理碎片)

特点:

如果内存不够分配新对象,就启动Serial Old收集器收集老年代

问题:如何保证收集线程和用户线程互不干扰地运行

增量更新算法:JVM---理解G1的SATB和CMS的增量更新_紫气东来_life的博客-CSDN博客_cms增量更新

G1-SATB、CMS-增量更新(文章记录)_OkidoGreen的博客-CSDN博客_cms 增量更新

G1收集器

特点:面向局部收集、基于Region的内存分布形式

衡量标准是哪块内存中垃圾数量最多,回收收益最大

有一类特殊的Humongous区域,专门用来存储大对象,基本看作老年代

从整体看是基于“标记-整理”,从局部看是基于“标记-复制”,不会产生空间碎片

默认采用的仍然是分代的方式,仍然坚信大多数新对象不需要长的生命周期

更细致分为fully young或partially young,fully young方式暂停的适合仅处理young regions,partially不仅处理,还会根据允许的GC的暂停时间来决定是否加入其他的非young regions

外部无法决定什么方式,启动时采用fully-young方式,一次Concurrent Marking后,切换为partially young方式

运作过程:

初始标记:标记Roots直接关联的对象,将region中top的值放入TAMS指针,每个region都保存了两个标识用的bitmap,包含一个bit的地址信息来指向对象的起始点

并发标记:可达性分析,扫描结束后重新处理SATB记录下的并发时有引用变动的对象

最终标记:短暂暂停,处理并发阶段结束后遗留下的SATB记录

筛选回收:自由选择任意多个Region构成回收集,把决定回收的那一部分Region的存活对象复制到空的Region中

跨Region引用的问题

每个Region维护自己的记忆集,记录下别的Region指向自己的指针,标记这些指针在哪些卡页的范围之内

G1的记忆集在存储结构的本质上是一种哈希表

问题:如何保证收集线程和用户线程互不干扰地运行

原始快照(SATB)算法

为每一个Region设计了两个名为TAMS的指针,把Region的一部分空间划分出来用于并发回收过程中的新对象分配,隐式标记,默认存活

建立起可靠停顿预测模型

记录回收耗时、脏卡数量,决定由哪些Region组成回收集

收集器的权衡

遗留系统,4GB到6GB以下的堆内存,使用CMS

选择收集器,三个问题:

1:应用程序的主要关注点

数据分析、科学计算:关注吞吐量

直接面向用户提供服务的B/S系统:降低停顿时间,低延迟

客户端或者嵌入式应用:内存占用

2:运行应用的基础设施

处理器数量、分配内存大小、系统架构、选择的操作系统

3:使用JDK的发行商和版本号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值