自己建一个网站需要什么,百度app下载最新版,知名品牌营销策略,wordpress显示文章简介图解 JVM 垃圾回收#xff08;二#xff09; 1.垃圾收集器1.1 内存分配与回收策略1.2 Serial 收集器1.3 Parallel Scavenge 收集器1.4 ParNew 收集器1.5 CMS 收集器1.6 G1 收集器 2.Full GC 的触发条件 1.垃圾收集器
Java 虚拟机提供了多种垃圾回收器#xff0c;每种回收器… 图解 JVM 垃圾回收二 1.垃圾收集器1.1 内存分配与回收策略1.2 Serial 收集器1.3 Parallel Scavenge 收集器1.4 ParNew 收集器1.5 CMS 收集器1.6 G1 收集器 2.Full GC 的触发条件 1.垃圾收集器
Java 虚拟机提供了多种垃圾回收器每种回收器有其特定的用途和优势。以下是常见的垃圾回收器 连线表示垃圾收集器可以配合使用。
单线程与多线程单线程指的是垃圾收集器只使用一个线程进行收集而多线程使用多个线程。串行与并行串行指的是垃圾收集器与用户程序交替执行这意味着在执行垃圾收集的时候需要停顿用户程序并行指的是垃圾收集器和用户程序同时执行。除了 CMS 和 G1 之外其它垃圾收集器都是以串行的方式执行。
1.1 内存分配与回收策略
JVM 在进行 GC 时并非每次都对堆内存新生代、老年代方法区区域一起回收的大部分时候回收的都是指新生代。
针对 HotSpot VM 的实现它里面的 GC 按照回收区域又分为两大类部分收集Partial GC整堆收集Full GC。
部分收集不是完整收集整个 Java 堆的垃圾收集。其中又分为 新生代收集Minor GC / Young GC只是新生代的垃圾收集。老年代收集Major GC / Old GC只是老年代的垃圾收集。目前只有 CMS GC 会有单独收集老年代的行为。很多时候 Major GC 会和 Full GC 混合使用需要具体分辨是老年代回收还是整堆回收。混合收集Mixed GC收集整个新生代以及部分老年代的垃圾收集。目前只有 G1 GC 会有这种行为。 整堆收集收集整个 Java 堆和方法区的垃圾。
1.2 Serial 收集器
-XX:UseSerialGC-XX:UseSerialOldGC
Serial 是一个单线程收集器了。它的 “单线程” 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程 “Stop The World” 直到它收集结束。 Serial 收集器由于没有线程交互的开销自然可以获得很高的单线程收集效率。Serial Old 收集器是 Serial 收集器的老年代版本它同样是一个单线程收集器。它主要有两大用途一种用途是在 JDK 1.5 以及以前的版本中与 Parallel Scavenge 收集器搭配使用另一种用途是作为 CMS 收集器的后备方案。新生代采用 复制 算法老年代采用 标记-整理 算法。
1.3 Parallel Scavenge 收集器
-XX:UseParallelGC新生代-XX:UseParallelOldGC老年代
Parallel 收集器其实就是 Serial 收集器的 多线程版本除了使用多线程进行垃圾收集外其余行为控制参数、收集算法、回收策略等等和 Serial 收集器类似。默认的收集线程数 跟 CPU 核数 相同当然也可以用参数-XX:ParallelGCThreads指定收集线程数但是一般不推荐修改。
Parallel Scavenge 收集器关注点是 吞吐量高效率的利用 CPU。CMS 等垃圾收集器的关注点更多的是用户线程的 停顿时间提高用户体验。所谓吞吐量就是 CPU 中用于运行用户代码的时间与 CPU 总消耗时间的比值。Parallel Scavenge 收集器提供了很多参数供用户找到最合适的停顿时间或最大吞吐量如果对于收集器运作不太了解的话可以选择把内存管理优化交给虚拟机去完成也是一个不错的选择。
新生代采用 复制 算法老年代采用 标记-整理 算法。
Parallel Old 收集器是 Parallel Scavenge 收集器的老年代版本。使用 多线程 和 标记-整理 算法。在注重吞吐量以及 CPU 资源的场合都可以优先考虑 Parallel Scavenge 收集器和 Parallel Old 收集器JDK 8 默认的新生代和老年代收集器。
1.4 ParNew 收集器
-XX:UseParNewGC新生代
ParNew 收集器其实跟 Parallel 收集器很类似区别主要在于它可以和 CMS 收集器配合使用。
新生代采用 复制 算法。
1.5 CMS 收集器
-XX:UseConcMarkSweepGC老年代
CMSConcurrent Mark SweepMark Sweep 指的是 标记-清除 算法。
CMS 收集器是一种以获取 最短回收停顿时间 为目标的收集器。它非常符合在注重用户体验的应用上使用它是 HotSpot 虚拟机第一款真正意义上的并发收集器它第一次实现了让垃圾收集线程与用户线程基本上同时工作。
它的运作过程相比于前面几种垃圾收集器来说更加复杂一些。整个过程分为四个步骤
初始标记 暂停所有的其他线程STW并记录下 GC Roots 直接能引用的对象速度很快。并发标记 并发标记阶段就是从 GC Roots 的直接关联对象开始遍历整个对象图的过程 这个过程耗时较长但是不需要停顿用户线程 可以与垃圾收集线程一起并发运行。因为用户程序继续运行可能会有导致已经标记过的对象状态发生改变。重新标记 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录主要是处理漏标问题这个阶段的停顿时间一般会比初始标记阶段的时间稍长远远比并发标记阶段时间短。主要用到三色标记里的增量更新算法做重新标记。并发清理 开启用户线程同时 GC 线程开始对未标记的区域做清扫。这个阶段如果有新增对象会被标记为黑色不做任何处理。并发重置重置本次 GC 过程中的标记数据。 CMS 主要优点并发收集、低停顿。但是它有下面几个明显的缺点
⭕ 对 CPU 资源敏感会和服务抢资源。⭕ 无法处理浮动垃圾在并发标记和并发清理阶段又产生垃圾这种浮动垃圾只能等到下一次 GC 再清理了。⭕ 它使用的 “标记-清除” 回收算法会导致收集结束时会有大量空间碎片产生通过参数 -XX:UseCMSCompactAtFullCollection 可以让 JVM 在执行完标记清除后再做整理往往出现老年代空间剩余但无法找到足够大连续空间来分配当前对象不得不提前触发一次 Full GC。⭕ 执行过程中的不确定性会存在上一次垃圾回收还没执行完然后垃圾回收又被触发的情况特别是在并发标记和并发清理阶段会出现一边回收系统一边运行也许没回收完就再次触发 Full GC也就是 “Concurrent Mode Failure”此时会进入 “Stop The World”用 Serial Old 垃圾收集器来回收。
1.6 G1 收集器
G1Garbage-First是一款面向服务端应用的垃圾收集器在多 CPU 和大内存的场景下有很好的性能。
堆被分为新生代和老年代其它收集器进行收集的范围都是整个新生代或者老年代而 G1 可以直接对新生代和老年代一起回收。G1 把堆划分成多个大小相等的 独立区域Region新生代和老年代不再物理隔离。 通过引入 Region 的概念从而将原来的一整块内存空间划分成多个的小空间使得每个小空间可以单独进行垃圾回收。这种划分方法带来了很大的灵活性使得可预测的停顿时间模型成为可能。通过记录每个 Region 垃圾回收时间以及回收所获得的空间这两个值是通过过去回收的经验获得并维护一个优先列表每次根据允许的收集时间优先回收价值最大的 Region。
每个 Region 都有一个 Remembered Set用来记录该 Region 对象的引用对象所在的 Region。通过使用 Remembered Set在做可达性分析的时候就可以避免全堆扫描。
G1 收集器的运作大致可划分为以下几个步骤:
初始标记Initial Marking仅仅只是标记一下 GC Roots 能直接关联到的对象。并发标记Concurrent Marking从 GC Roots 开始对堆中对象进行可达性分析递归扫描整个堆里的对象图找出要回收的对象这阶段耗时较长但可与用户程序并发执行。最终标记Final Marking对用户线程做另一个短暂的暂停用于处理并发阶段结束后仍遗留下来的最后那少量的 SATBSnapshot At The Beginning原始快照记录。筛选回收Live Data Counting and Evacuation负责更新 Region 的统计数据对各个 Region 的回收价值和成本进行排序根据用户所期望的停顿时间来制定回收计划可以自由选择任意多个 Region 构成回收集然后把决定回收的那一部分 Region 的存活对象复制到空的 Region 中再清理掉整个旧 Region 的全部空间。这里的操作涉及存活对象的移动是必须暂停用户线程由多条收集器线程并行完成的。
它具备以下特点
并行与并发G1 能充分利用 CPU、多核环境下的硬件优势使用多个 CPUCPU 或者 CPU 核心来缩短 Stop-The-World 停顿时间。部分其他收集器原本需要停顿 Java 线程执行的 GC 动作G1 收集器仍然可以通过并发的方式让 Java 程序继续执行。分代收集虽然 G1 可以不需要其他收集器配合就能独立管理整个 GC 堆但是还是保留了分代的概念。空间整合与 CMS 的 “标记-清除” 算法不同G1 从整体来看是基于 “标记-整理” 算法实现的收集器从局部上来看是基于 “标记-复制” 算法实现的。可预测的停顿这是 G1 相对于 CMS 的另一个大优势降低停顿时间是 G1 和 CMS 共同的关注点但 G1 除了追求低停顿外还能建立可预测的停顿时间模型能让使用者明确指定在一个长度为 M 毫秒的时间片段内消耗在垃圾收集上的时间不得超过 N 毫秒。 G1 收集器在后台维护了一个优先列表每次根据允许的收集时间优先选择回收价值最大的 Region这也就是它的名字 Garbage-First 的由来。这种使用 Region 划分内存空间以及有优先级的区域回收方式保证了 G1 收集器在有限时间内可以尽可能高的收集效率把内存化整为零。
从 JDK 9 开始G1 垃圾收集器成为了默认的垃圾收集器。
2.Full GC 的触发条件
对于 Minor GC其触发条件非常简单当 Eden 空间满时就将触发一次 Minor GC。而 Full GC 则相对复杂有以下条件:
调用 System.gc() 只是建议虚拟机执行 Full GC但是虚拟机不一定真正去执行。不建议使用这种方式而是让虚拟机管理内存。老年代空间不足。老年代空间不足的常见场景为前文所讲的大对象直接进入老年代、长期存活的对象进入老年代等。为了避免以上原因引起的 Full GC应当尽量不要创建过大的对象以及数组。除此之外可以通过 -Xmn 虚拟机参数调大新生代的大小让对象尽量在新生代被回收掉不进入老年代。还可以通过 -XX:MaxTenuringThreshold 调大对象进入老年代的年龄让对象在新生代多存活一段时间。空间分配担保失败。使用复制算法的 Minor GC 需要老年代的内存空间作担保如果担保失败会执行一次 Full GC。JDK 1.7 及以前的永久代空间不足1.7 之后元空间不足。在 JDK 1.7 及以前HotSpot 虚拟机中的方法区是用永久代实现的永久代中存放的为一些 Class 的信息、常量、静态变量等数据。当系统中要加载的类、反射的类和调用的方法较多时永久代可能会被占满在未配置为采用 CMS GC 的情况下也会执行 Full GC。如果经过 Full GC 仍然回收不了那么虚拟机会抛出 java.lang.OutOfMemoryError。为避免以上原因引起的 Full GC可采用的方法为增大永久代空间或转为使用 CMS GC。Concurrent Mode Failure。执行 CMS GC 的过程中同时有对象要放入老年代而此时老年代空间不足可能是 GC 过程中浮动垃圾过多导致暂时性的空间不足便会报 Concurrent Mode Failure 错误并触发 Full GC。