JVM垃圾回收机制及算法

栈: 栈中的生命周期是跟随线程,所以不是关注的重点
堆: 堆中的对象是共享的,也是存活时间比较长的,所以是重点。
新生代采用是复制回收算法,老年代采用的标记清除,标记整理算法。
 
 
复制算法( Copying
就是将from区和to区分成1:1,然后当发生新生代GC Minor GC/Young GC两者叫法不一样,其实意思都是年轻代的GC)的时候,会把from区的数据复制到to区去,然后格式化from区的对象。再发生Minor GC/Young的时候重新把to区的对象又复制到from区去,然后格式化to区的对象,这个就是复制回收算法,所以这就是为什么from和to是1:1的原因。
这个算法的特点如下:
1,因为要留一半空间回收,导致空间利用率只有一半。
2,内存分配时也就不用考虑内存碎片等复杂情况,实现简单,运行高效
 
Appel 式回收
这是专门针对Eden区回收的一种方式,
新生代中的对象 98% 是“朝生夕死”的,所以整个年轻代并不需要按照 1:1 的比例来划分内存空间,这样会很浪费空间,
因为对象首先都是在这个区域产生的,10%的内存会被“浪费”。所以 HotSpot 虚拟机默认 Eden from还有to区  的大小比例是
8:1:1.
 
Appel 式回收具体的实现方式就是当发生GC的时候第一次会把Eden区的对象丢到from区,第二次GC的时候把from区和Eden区的对象放到to区,第三次就是把Eden区和to区的对象重新放到from区,依次反复,当对象年龄等于15的时候直接到老年代了,如果对象很大,from或者to区放不下的话也放到老年代。
 
标记 - 清除算法( Mark-Sweep
顾名思义就是标记+清除两个阶段,他的特点就是尽量会进行扫描标记两次,然后清除但是会产生大量的内存碎片,
标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连 续内存而不得不提前触发另一次垃圾回收动作。
 
标记 - 整理算法( Mark-Compact
顾名思义就是标记+整理两个阶段,,他的特点就是尽量会进行扫描标记两次,然后整理清除,内存不会产生碎片,但是整理后再清除效率会很低,还会移动对象的内存地址, 直接指针需要调整。
 
JVM 中常见的垃圾回收器
 
 
Serial/Serial Old
JVM 刚诞生就只有这种,最古老的,单线程,独占式,成熟,适合单 CPU ,一般用在客户端模式下。
这种垃圾回收器只适合几十兆到一两百兆的堆空间进行垃圾回收(可以控制停顿时间再 100ms 左右),但是对于超过这个大小的内存回收速度很慢。
 
Parallel Scavenge ParallerGC /Parallel Old
为了提高回收效率,从 JDK1.3 开始, JVM 使用了多线程的垃圾回收机制,关注吞吐量的垃圾收集器,高吞吐量则可以高效率地利用 CPU 时间,尽快完成
程序的运算任务,主要适合在后台运算而不需要太多交互的任务。
所谓吞吐量就是 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值,即吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间),虚拟机总
共运行了 100 分钟,其中垃圾收集花掉 1 分钟,那吞吐量就是 99%
该垃圾回收器适合回收堆空间 上百兆 ~ 几个 G
JDK1.8 默认就是以下组合
-XX:+UseParallelGC 新生代使用 Parallel Scavenge ,老年代使用 Parallel Old
 
 
Concurrent Mark Sweep CMS
 
 
1 初始标记,STW的时间很短,因为 仅仅只是标记一下 GC Roots 能直接关联到的对象,速度很快
2 并发标记,这个时候就会去GC Roots根节点下面找要回收的对象,和其他用户线程并行,不会STW,但是时间很长
3 重新标记,为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段稍长一些,但远比并发标记的时间短
4 并发清理,由于整个过程中耗时最长的并发标记和并发清除过程收集器线程都可以与用户线程一起工作,所以,从总体上来说,CMS 收集器的内存回收过程是与用
户线程一起并发执行的。
-XX:+UseConcMarkSweepGC ,表示新生代使用 ParNew ,老年代的用 CMS
 
 
总结特点
   1,CMS 对处理器资源敏感,毕竟采用了并发的收集、当处理核心数不足 4 个时, CMS 对用户的影响较大。
   2,浮动垃圾:当并发清理的时候不暂停用户线程,清理的过程中用户线程又可能产生垃圾,这个就叫浮动垃圾,只能等下一次GC的时候才会清理了。
由于浮动垃圾的存在,因此需要预留出一部分内存,意味着 CMS 收集不能像其它收集器那样等待老年代快满的时候再回收。
1.6 的版本中老年代空间使用率阈值 (92%)
如果预留的内存不够存放浮动垃圾,就会出现 Concurrent Mode Failure ,这时虚拟机将临时启用 Serial Old 来替代 CMS

   3,会产生空间碎片

  CMS 采用了标记清除算法,所以会有内存碎片,

当碎片较多时,给大对象的分配带来很大的麻烦,为了解决这个问题, CMS 提供一个
参数: -XX:+UseCMSCompactAtFullCollection ,一般是开启的,如果分配不了大对象,就进行内存碎片的整理过程。
这个地方一般会使用 Serial Old ,因为 Serial Old 是一个单线程,所以如果内存空间很大、且对象较多时 ,CMS 发生这样情况会很卡。
 
 
Garbage First(G1)
设计思想
随着 JVM 中内存的增大, STW 的时间成为 JVM 急迫解决的问题,但是如果按照传统的分代模型,总跳不出 STW 时间不可预测这点。
为了实现 STW 的时间可预测,首先要有一个思想上的改变。 G1 将堆内存“化整为零”,将堆内存划分成多个大小相等独立区域( Region ),每一个 Region
都可以根据需要,扮演新生代的 Eden 空间、 Survivor 空间,或者老年代空间。回收器能够对扮演不同角色的 Region 采用不同的策略去处理,这样无论是
新创建的对象还是已经存活了一段时间、熬过多次收集的旧对象都能获取很好的收集效果
 
Region
Region 可能是 Eden, 也有可能是 Survivor, 也有可能是 Old, 另外 Region 中还有一类特殊的 Humongous 区域,专门用来存储大对象。 G1 认为只要大小超过
了一个 Region 容量一半的对象即可判定为大对象。每个 Region 的大小可以通过参数 -XX:G1HeapRegionSize 设定,取值范围为 1MB~32MB, 且应为 2 N
幂。而对于那些超过了整个 Region 容量的超级大对象,将会被存放在 N 个连续的 Humongous Region 之中, G1 的进行回收大多数情况下都把 Humongous
Region 作为老年代的一部分来进行看待。
参数设置
开启参数
-XX:+UseG1GC
分区大小
-XX:+G1HeapRegionSize 一般建议逐渐增大该值,随着 size 增加,垃圾的存活时间更长, GC 间隔更长,但每次 GC 的时间也会更长。
 
1,初始标记   和cms一样,短暂的暂停线程,
仅仅只是标记一下 GC Roots 能直接关联到的对象,并且修改 TAMS 指针的值,让下一阶段用户线程并发运行时,能正确地在可用的 Region 中分配新对象。
这个阶段需要停顿线程,但耗时很短
TAMS 是什么?
要达到 GC 与用户线程并发运行,必须要解决回收过程中新对象的分配,所以 G1 为每一个 Region 区域设计了两个名为 TAMS Top at Mark Start )的指针,
Region 区域划出一部分空间用于记录并发回收过程中的新对象。这样的对象认为它们是存活的,不纳入垃圾回收范围。
2,并发标记   和cms一样,和用户线程一起
当对象图扫
描 完 成 以 后 , 并 发 时 有 引 用 变 动 的 对 象 , 这 些 对 象 会 漏 标 , 漏 标 的 对 象 会 被 一 个 叫 做
SATB(snapshot-at-the-beginning)算法来解决
3, 最终标记 ( Final Marking)
对用户线程做另一个短暂的暂停,用于处理并发阶段结后仍遗留下来的最后那少量的 SATB 记录 ( 漏标对象 )
4, 筛选回收 ( Live Data Counting and Evacuation)
负责更新 Region 的统计数据,对各个 Region 的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个 Region
成回收集,然后把决定回收的那一部分 Region 的存活对象复制到空的 Region 中,再清理掉整个旧 Region 的全部空间。这里的操作涉及存活对象的移动,
是必须暂停用户线程,由多条收集器线程并行完成的
 
 
 
特点
并行与并发 G1 能充分利用多 CPU 、多核环境下的硬件优势,使用多个 CPU CPU 或者 CPU 核心)来缩短 Stop-The-World 停顿的时间,部分其他收集器
原本需要停顿 Java 线程执行的 GC 动作, G1 收集器仍然可以通过并发的方式让 Java 程序继续执行。
分代收集 :与其他收集器一样,分代概念在 G1 中依然得以保留。虽然 G1 可以不需要其他收集器配合就能独立管理整个 GC 堆,但它能够采用不同的方式
去处理新创建的对象和已经存活了一段时间、熬过多次 GC 的旧对象以获取更好的收集效果。
空间整合 :与 CMS 的“标记—清理”算法不同, G1 从整体来看是基于“标记—整理”算法实现的收集器,从局部(两个 Region 之间)上来看是基于“复
制”算法实现的,但无论如何,这两种算法都意味着 G1 运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。这种特性有利于程序长时间运
行,分配大对象时不会因为无法找到连续内存空间而提前触发下一次 GC
追求停顿时间:
-XX:MaxGCPauseMillis 指定目标的最大停顿时间, G1 尝试调整新生代和老年代的比例,堆大小,晋升年龄来达到这个目标时间。
怎么玩?
该垃圾回收器适合回收堆空间上百 G 。一般在 G1 CMS 中间选择的话平衡点在 6~8G ,只有内存比较大 G1 才能发挥优势。
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值