jvm垃圾回收

2 篇文章 0 订阅
2 篇文章 0 订阅

一、判断垃圾算法

1、引用计数法

给每个对象添加一个计数器,当有地方引用该对象时计数器加1,当引用失效时计数器减1。用对象计数器是否为0来判断对象是否可被回收。缺点:无法解决循环引用的问题

2、可达性分析法

通过GC ROOT的对象作为搜索起始点,通过引用向下搜索,所走过的路径称为引用链。通过对象是否有到达引用链的路径来判断对象是否可被回收(可作为GC ROOT的对象:虚拟机栈中引用的对象,方法区中类静态属性引用的对象,方法区中常量引用的对象,本地方法栈中JNI引用的对象)

二、垃圾回收算法

1、标记-清除(Mark-Sweep)

  • 标记需要回收的对象
  • 清理掉要回收的对象
    标记-清除法

2、标记-整理(Mark-Compact)

  • 标记需要回收的对象
  • 把所有的存活对象压缩到内存一端
  • 清理掉边界外的所有空间
  • 避免内存随便产生
    标记-整理

3、复制(Copy)

  • 把内存分为两块,每次只是用一块
  • 将正在使用的内存中的存活对象复制到未使用的内存中去,然后清除掉正在使用的内存中的所有对象
  • 交换两个内存的角色,等待下次回收
    复制
    三种算法对比
回收算法优点缺点
标记-清除实现简单存在内存碎片、分配内存速度会受影响
标记-整理无碎片整理存在开销
复制性能好、无碎片内存利用率低

4、分代收集算法

  • 把内存分成多个区域,不同区域使用不同的回收算法回收对象
  • 根据对象的存活周期,把内存分成多个区域,不同区域使用不同的回收算法回收对象

优点

  • 更有效的清除不在需要的对象
  • 提升了垃圾回收的效率
    调优原则
  • 合理设置Survivor区域的大小,避免内存浪费
  • 让GC尽量发生在新生代,尽量减少Full GC的发生

5、增量算法

  • 每次只收集一小片区域的内存空间的垃圾

三、垃圾分布和触发条件

1、 堆内存结构

堆内存结构

  • 新对象一般分配到Eden区
    • 对象大于 -XX:PretenureSizeThreshold,就会直接分配到老年代
    • 新生代空间不够的时候也会分配到老年代
  • 对象不一定要到达到年龄才会进入老年代
    • 动态年龄:如果Survivor空间中所有相同年龄对象大小的总和大于Survivor空间的一半,那么年龄大于等于该年龄的对象就可以直接进入老年代

2、回收类型

  • 新生代回收(Minor GC | Young GC)
  • 老年代回收(Major GC)
  • 清理整个堆(Full GC)
  • Major GC ≈ Full GC

3、触发垃圾回收的条件

3.1、新生代
  • Eden区空间不足
3.2、老年代
  • 老年代空间不足
  • 元空间不足
  • 要晋升到老年代的对象所占用的空间大于老年代的剩余空间
  • 显示调用System.gc()
    • 建议垃圾回收期执行垃圾回收
    • -XX:+DisableExplicitGC 参数,忽略掉System.gc()的调用

四、垃圾收集器

  • 垃圾收集算法:为实现垃圾回收提供理论支持
  • 垃圾收集器:利用垃圾收集算法,实现垃圾回收的具体实现
    垃圾收集器
  • 术语-Stop The World
    • 简写为STW,也叫全局停顿,Java代码停止运行,native代码继续运行,但不能于jvm进行交互
    • 原因:多半由于垃圾回收导致;也可能由Dump线程、死锁检查、Dump堆等导致
    • 危害:服务停止、没有响应;主从切换、危害生产环境
  • 术语-并行收集 vs 并发收集
    • 并行收集:指多个垃圾收集线程并行工作,但是收集的过程中,用户线程(业务线程)还是处于等待状态的
    • 并发收集:之用户线程与垃圾收集线程同时工作

1、新生代收集器

1.1、Serial 收集器
  • 最基本的、发展历史最悠久的收集器
  • 复制算法
    Serial 收集器
    特点
  • 单线程
  • 简单、高效
  • 收集过程全程Stop The World

适用场景

  • 客户端程序,应用以-client模式运行时,默认使用的就是Serial
  • 单核机器

1.2、 ParNew收集器

  • Serial收集器的多线程版,除使用了多线程以外,其他和Serial收集器一样,包括:JVM参数、Stop The World 的表现、垃圾收集算法都是一样的

ParNew收集器
特点

  • 多线程
  • 可使用-XX:ParallelGCThreads设置垃圾收集的线程数

适用场景

  • 主要用来和CMS收集器配合使用
1.3、Parallel Scavenge收集器
  • 也叫吞吐量优先收集器
  • 采用的也是复制算法
  • 也是并行的多线程收集器,这一点和ParNew类似
    Parallel Scavenge收集器
    特点
  • 可以达到一个可控制的吞吐量
    • -XX:MaxGCPauseMillis 控制最大的垃圾收集停顿时间(尽力)
    • -XX:GCTimeRatio 设置吞吐量的大小,取值0-100,系统花费不超过1/(1+n)的时间用于垃圾收集
  • 自适用GC策略:可用-XX:+UseAdptiveSizePolicy打开
    • 打开自适应策略后,无需手动设置新生代的大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRatio)等参数
    • 虚拟机会自动根据系统的运行状况收集性能监控信息,动态地调整这些参数,从而达到最优的停顿时间以及最高的吞吐量

适用场景

  • 注重吞吐量的场景

2、老年代收集器

2.1、Serial Old 收集器
  • Serial 收集器的老年代版
  • 标记-整理算法
    Serial Old 收集器
    适用场景
  • 可以和Serial/ParNew/Parallel Scavenge这三个新生代的垃圾收集器配合适用
  • CMS收集器出现故障的时候,会用Serial Old最为后备
2.2、Parallel Old收集器
  • Parallel Scavenge 收集器的老年代版本
  • 标记-整理算法
    Parallel Old收集器
    适用场景
  • 关注吞吐量的场景
2.3、CMS收集器
  • CMS:Concurrent Mark Sweep
  • 并发收集器
  • 标记-清除算法
    CMS收集器
    执行过程
  1. 初始标记(initial mark)
    -标记GC Roots能直接关联到的对象
    -Stop The World
  2. 并发标记(concurrent mark)
    -找出所有的GC Roots 能关联到的对象
    -并发执行,无Stop The World
  3. 并发预清理(concurrent-preclean)
    -重新标记那些在并发标记阶段,引用被更新的对象,从而减少后面重新标记阶段的工作量
    -并发执行,无Stop The World
    -可适用-XX:-CMSPrecleaningEnabled 关闭并发预清理阶段,默认打开
  4. 并发可中止的预清理阶段(concurrent-abortable-preclean)
    -和并发预清理做的事情一样,并发执行,无Stop The World
    -当Eden的适用量大于CMSScheduleRemarkEdenSizeThreshold的阈值(默认2M)时,才会执行该阶段
    -主要作用:允许我们能够控制预清理阶段的结束时机。比如扫描多长时间(CMSMaxAbortablePrecleanTime,默认5秒)或者Eden区使用占比达到一定阈值(CMSScheduleRemarkEdenPenetration,默认50%)就结束本阶段
  5. 重新标记(remark)
    -修正并发标记期间,因为用户程序继续运行,导致标记发生变动的那些对象
    -一般来说,重新标记花费的时间会比初始标记阶段长一些,但比并发标记时间短
    -存在Stop The World
  6. 并发清除(concurrent sweep)
    -基于标记结果,清除掉要清除前面标记出来的垃圾
    -并发执行,无Stop The World
    (为什么不是并发整理呢?用户线程还在运行)
  7. 并发重置(concurrent reset)
    -清理本次CMS GC 的上下文信息,为下一次GC做准备

优点

  1. Stop The World 的时间比较短
  2. 大多过程并发执行

缺点

  1. CPU资源比较敏感,并发阶段可能导致应用吞吐量的降低
  2. 无法处理浮动垃圾
  3. 不能等到老年代几乎满了才开始收集
    -预留的内存不够 -> Concurrent Mode Failure -> Serial Old 作为后备
    -可使用CMSInitiatingOccupancyFraction 设置老年代占比达到多少就触发垃圾收集,默认68%
  4. 内存碎片
    *标记-清除导致碎片的产生
    *UseCMSCompactAtFullCollection,在完成Full GC后是否要进行内存碎片整理,默认开启
    *CMSFullGCsBeforeCompaction,进行几次Full GC后就进行一次内存碎片整理,默认0

适用场景

  • 希望系统听读那时间短,响应速度快的场景,比如各种服务器,应用程序

总结

  1. 初始标记(STW)
  2. 并发标记
  3. 并发预清理
  4. 并发可中止预清理
  5. 重新标记(STW)
  6. 并发清除
  7. 并发重置
2.4、G1收集器
  • Garbge First
  • 面向服务器端应用的垃圾收集器
    G1收集器
    Region
  • 通过参数-XX:G1HeapRegionSize 指定Region的大小
  • 取值范围为1Mb ~ 32 Mb,应为2的N次幂

设计思想

  • 内存分块(Region)
  • 跟踪每个Region里面的垃圾堆积的价值大小
  • 构建一个优先列表,根据允许的收集时间,优先回收价值高的Region

垃圾收集机制

  1. Young GC
    • 所有Eden Region 都满了的时候,就会触发Young GC
    • Eden 里面的对象会转移到Survivor Region里面去
    • 原先Survivor Region 中的对象转移到新的Survivor Region中,或者晋升到Old Region
    • 空闲Region 会被放入空闲列表中,等待下次被适用
  2. Mixed GC
    • 老年代大小占整个堆的百分比达到一定阈值(-XX:InitiationgHeapOccupancyPercent指定,默认45%),就触发
    • Mixed GC会回收所有Young Region,同时回收部分Old Region
      G1收集器
      Mixed GC执行过程
  • 初始标记(Initial Marking)
    • 标记GC Roots 能直接关联到的对象,和CMS类似
    • 存在 Stop The World
  • 并发标记(Concurrent Marking)
    • 同CMS的并发标记
    • 并发执行,没有Stop The World
  • 最终标记(Final Marking)
    • 修正在并发标记期间引起的变动
    • 存在Stop The World
  • 筛选回收(Live Data Countion and Evacuation)
    • 对各个Region的回收价值和成本进行排序
    • 根据用户所期望的停顿时间(MaxGCPauseMillis)来制定回收计划,并 选择一些Region回收
  • 回收过程
    • 选择一系列Region构成一个回收集
    • 把决定回收的Region中的存活对象复制到空的Region中
    • 删除掉需要回收的Region -> 无内存碎片
    • 存在Stop The World
  1. Full GC
    • 复制对象内存不够,或者无法分配足够内存(比如巨型对象没有足够的连续分区分配)时,会触发Full GC
    • Full GC模式下,使用 Serial Old 模式
    • G1优化原则:尽量 减少Full GC的发生
      *增加预留内存(增大 -XX:G1ReservePercent,默认为堆的10%)
      *更早地回收垃圾(减少 -XX:InitiatingHeapOccupancyPercent,老年代达到该值就触发Mixed GC,默认45%)
      *增加并发阶段使用的线程数(增大 -XX:ConcGCThreads)

特点

  • 可以作用在整个堆
  • 可控的停顿(MaxGCPauseMillis=200)
  • 无内存碎片

适用场景

  • 占用内存较大的应用(6G以上)
  • 替换CMS垃圾收集器

总结

  • 内存分Region
  • 包括Young GC、Mixed GC、Full GC
  • Mixed GC 步骤和CMS有类似之处,但也有很多差异

G1 or CMS ?

  • 对于JDK 8:都可以使用。如果内存<=6G,建议使用CMS,反之使用G1
  • 如果高于JDK 8:用G1,CMS从JDK9已经被废弃了

五、调优

参数作用参考值
-XX:NewRatio=n老年代:新生代内存大小比值2
-XX:SurvivorRatio=nEden区:Survivor区内存大小比值8
-XX:PretenureSizeThreshold=n对象大于该值就在老年代分配,0标识不做限制15
-Xms最小堆内存-
-Xmx最大堆内存-
-Xmn新生代大小-
-XX:+DisableExpilcitGC忽略掉System.gc()的调用启用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值