转载

JVM之垃圾收集(Garbage Collection [Ⅱ])

垃圾收集器就是内存回收操作的具体实现,HotSpot 有 7 种。因为它们各有各的适用场景。有的属于新生代收集器,有的属于老年代收集器,所以一般都是搭配使用的。关于它们的简单介绍以及分类请见下图。

JVM之垃圾收集(Garbage Collection [Ⅱ])

Serial 收集器

JVM之垃圾收集(Garbage Collection [Ⅱ])

特点:

1.“单线程”操作。会产生“Stop The World”。
2.采用"Stopr the world"。
3.Serial 收集器是虚拟机在 Client模式下的默认新生代收集器,它的优势是简单高效,适合单 CPU 模式。
复制代码

ParNew 收集器

JVM之垃圾收集(Garbage Collection [Ⅱ])
特点:
1.其本身就是 Serial 收集器的多线程版本。虽然除此之外没什么创新之处,但它却是许多运行在 Server 模式下的虚拟机中的首选新生代收集器。

2.除了 Serial 收集器外,只有它能和 CMS 收集器搭配使用。
复制代码

Parallel Scavenge 收集器

JVM之垃圾收集(Garbage Collection [Ⅱ])
特点:
1.新生代收集器,并行的多线程收集器。
2.使用复制算法,
3.可控制吞吐量(Throughput)。
复制代码

吞吐量 = 运行用户代码时间 / ( 运行用户代码时间 + 垃圾收集时间 )

可调节的虚拟机参数:

  • -XX:MaxGCPauseMillis :最大 GC 停顿的秒数;
  • -XX:GCTimeRatio :吞吐量大小,一个 0 ~ 100 的数, 最大 GC 时间占总时间的比率 = 1 / (GCTimeRatio + 1)
  • -XX:+UseAdaptiveSizePolicy :一个开关参数,打开后就无需手工指定 -Xmn-XX:SurvivorRatio 等参数了,虚拟机会根据当前系统的运行情况收集性能监控信息,自行调整。

Serial Old 收集器

JVM之垃圾收集(Garbage Collection [Ⅱ])
特点:
1.Serial收集器的老年代版,同为单线程。
2.使用标记整理算法。
3.作为CMS收集容器的后备预案。
复制代码

Prallel Old 收集器

JVM之垃圾收集(Garbage Collection [Ⅱ])
特点:
1.Parallel Old收集器的老年代版,多线程。
2.使用标记-整理算法。
复制代码

CMS 收集器(Concurrent Mark Sweep)

JVM之垃圾收集(Garbage Collection [Ⅱ])

特点:

1.CMS注重于服务的响应速度,希望系统停顿时间最短。
2.基于“标记-清除”算法实现的。【注1】
3.存在以下几点缺点:
    (1)CMS收集器对CPU资源非常敏感。
    (2)CMS收集器无法处理浮动垃圾。
    (3)由于基于标记-清除算法,所以会产生大量碎片
复制代码

【注1】 标记-清除算法步骤: 1.初始标记 2.并发标记 3.重新标记 4.并发清除

参数设置:

-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction

关于 CMS 使用 标记 - 清除 算法的一点思考:

之前对于 CMS 为什么要采用 标记 - 清除 算法十分的不理解,既然已经有了看起来更高级的 标记 - 整理 算法,那 CMS 为什么不用呢?最近想了想,感觉可能是这个原因,不过也不是很确定,只是个人的一种猜测。

标记 - 整理 会将所有存活对象向一端移动,然后直接清理掉边界以外的内存。这就意味着需要一个指针来维护这个分隔存活对象和无用空间的点,而我们知道 CMS 是并发清理的,虽然我们启动了多个线程进行垃圾回收,不过如果使用 标记 - 整理 算法,为了保证线程安全,在整理时要对那个分隔指针加锁,保证同一时刻只有一个线程能修改它, 加锁的这一过程相当于将并行的清理过程变成了串行的,也就失去了并行清理的意义了。

所以,CMS 采用了 标记 - 清除 算法。

G1 收集器

JVM之垃圾收集(Garbage Collection [Ⅱ])

特点:1.并行并发。 2.分代收集。 3.空间整合。 4.可预测的停顿。

G1运算步骤

1.初始标记
2.并发标记
3.最终标记
4.筛选回收
复制代码

GC 日志解读

JVM之垃圾收集(Garbage Collection [Ⅱ])

Java 内存分配策略

新生代和老年代的 GC 操作:

  • 新生代 GC 操作:Minor GC
    • 发生的非常频繁,速度较块。
  • 老年代 GC 操作:Full GC / Major GC
    • 经常伴随着至少一次的 Minor GC;
    • 速度一般比 Minor GC 慢上 10 倍以上。

优先在 Eden 区分配

  • Eden 空间不够将会触发一次 Minor GC;
  • 虚拟机参数:
    -Xmx
    -Xms
    -Xmn
    -XX:SurvivorRatio=8
    

大对象直接进入老年代

  • 大对象定义: 需要大量连续内存空间的 Java 对象。例如那种很长的字符串或者数组。
  • 设置对象直接进入老年代大小限制:
    • -XX:PretenureSizeThreshold :单位是字节;
      • 只对 Serial 和 ParNew 两款收集器有效。
    • 目的: 因为新生代采用的是复制算法收集垃圾,大对象直接进入老年代可以避免在 Eden 区和 Survivor 区发生大量的内存复制。

长期存活的对象将进入老年代

  • 固定对象年龄判定: 虚拟机给每个对象定义一个年龄计数器,对象每在 Survivor 中熬过一次 Minor GC,年龄 +1,达到 -XX:MaxTenuringThreshold 设定值后,会被晋升到老年代, -XX:MaxTenuringThreshold 默认为 15;
  • 动态对象年龄判定: Survivor 中有相同年龄的对象的空间总和大于 Survivor 空间的一半,那么,年龄大于或等于该年龄的对象直接晋升到老年代。
原文  https://juejin.im/post/5dd0eaaa518825107d3e42c0
正文到此结束
Loading...