JVM-垃圾收集器

1. 介绍

1.1 为什么需要垃圾收集器

       堆中存放着正在运行的JAVA程序所创建的所有对象,例如使用new指令创建对象。但是没有明确代码来释放它们,垃圾收集就是自动释放不再被程序使用的对象的过程。

1.2 如何判断垃圾对象

  • 引用计数法

       缺点:循环引用问题

  • 可达性分析法

       GCroot结点开始向下搜索,路径称为引用链,当对象没有任何一条引用链链接的时候,就认为这个对象是垃圾,并进行回收。如果在“GC roots”和一个对象之间没有可达路径,则称该对象是不可达的。要注意的是,不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收

       目前主流JVM采用的垃圾判定算法就是可达性分析法。JAVA代码方法中并不是所有创建的对象都是在栈的本地变量表中的,例如创建一个Person局部变量,其中给这个Person对象再赋值baby对象,则堆中的指向关系为下图的⑥,并不是栈去记录的。

 1.4 GCroot对象

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等。
  • 在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。
  • 在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。
  • 在本地方法栈中JNI(即通常所说的Native方法)引用的对象。
  • Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
  • 所有被同步锁(synchronized关键字)持有的对象。
  • 反映Java虚拟机内部情况的JM XBean、JVM TI中注册的回调、本地代码缓存等

1.5 垃圾收集算法

  • 标记-清除

       标记对象,然后清理

       缺点:内存碎片多

  • 复制

       区分Eden、Survivor From、Survivor To三个区域,每次将Eden区、Survivor From/Survivor To区复制幸存对象到另一个幸存区,然后直接清理垃圾对象。Yong GC采用这种模式,原因是新生代对象生成频繁,大多对象生命周期短,需要频繁回收垃圾对象,而复制算法是效率最快的,相对于另外两种,但是会浪费一点空间,默认的比例是Eden:Survivor From:Survivor To=8:1:1 。

       PS:内存地址会变动,但是对象的hashCode不会变动

  • 标记-整理

       标记对象,然后将幸存对象移动到内存的一端,然后清除垃圾对象。老年代Full GC会使用这种方式,内存利用率高。

1.6 垃圾收集器分类

        对于Java7引入的G1,以及Java11引入的ZGC和Java12引入的Shenandoah GC,这三者都是作用于整个堆的回收器(G1相比后两者有点不同,G1严格意义上也是区分新生代和老年代的)。Yong GC核心算法就是复制, Full GC核心算法就是标记-整理。

  • Serial

       单线程,慢,客户端模式默认年轻代垃圾收集方式(目前JAVA HotSpot 默认都是服务端模式)。

  • ParNew

       多线程,默认开启CPU 数目相同的线程数,可以通过-XX:ParallelGCThreads 参数来限制垃圾收集器的线程数

  • Parallel Scavenge

       多线程,可控制的吞吐量(吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)),服务端模式默认首选。收集器还有一个参数-XX:+UseAdaptiveSizePolicy值得关注。这是一个开关参数,当这个参数打开之后,就不需要手工指定新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量,这种调节方式称为GC自适应的调节策略(GC Ergonomics)。如果读者对于收集器运作原来不太了解,手工优化存在困难的时候,使用Parallel Scavenge收集器配合自适应调节策略,把内存管理的调优任务交给虚拟机去完成将是一个不错的选择。只需要把基本的内存数据设置好(如-Xmx设置最大堆),然后使用MaxGCPauseMillis参数(更关注最大停顿时间)或GCTimeRatio(更关注吞吐量)参数给虚拟机设立一个优化目标,那具体细节参数的调节工作就由虚拟机完成了。自适应调节策略也是Parallel Scavenge收集器与ParNew收集器的一个重要区别。

  • CMS(Concurrent Mark Sweep)

     多线程,标记清除算法

  • Serial Old

     单线程,慢

  • Paraller Old

     多线程,标记整理,jvm运行Server模式默认收集器

  • G1

      G1其实是Garbage First的意思,垃圾优先? 不是,是优先处理那些垃圾多的内存块的意思。去除内存碎片问题,同时保留CMS垃圾收集器低暂停时间的优化。jdk1.7推出,jdk9默认收集方式,代替CMS。G1垃圾收集器相对比其他收集器而言,大的区别在于它取消了年轻代、老年代的物理划分,取而代之的是将堆划分为若干个区域(Region),这些区域中包含了有逻辑上的年轻代、老年代区域(分治)。

G1回收步骤:

(1) 初始标记

      STW,标记GC ROOTS无法关联到的对象。用时很短。

(2) 并发标记

       与用户线程同时执行,将初始标记中所获取到的GC ROOTS对象进行追踪,找到需要回收的对象和不需要回收的对象。用时最长。

(3) 重新标记

       STW,这一步是为了标记到在并发标记中,用户线程所产生的新的可回收对象。用时较短。

(4) 筛选回收

       与用户线程同时执行,通过对区域的回收价值列表以及预测回收时间的综合分析,对可回收的区域进行筛选并回收掉,采用的是复制算法。用时为用户掉预测回收时间。这里的耗时是用户设置的最大垃圾回收时间,可通过-XX:MaxGCPauseMillis=parseMIlls来设置。

1.7 不同JDK版本垃圾收集器的区别

  • jdk1.7 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
  • jdk1.8 默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
  • jdk1.9 默认垃圾收集器G1

2. FAQ

2.1 复制算法和标记整理算法有什么区别?

      这两类都分两个步骤:移动对象和清除数据。清除数据两者效率应该都差不多。移动对象的话整理要比复制的多(对象的复制次数)

2.2 三色标记法?

3. 参考资料

G1 垃圾收集器架构和如何做到可预测的停顿(阿里)

垃圾收集器原理

GC复制存活的对象,内存地址会变吗?以前的引用怎么办?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值