JVM中垃圾收集算法主要有复制算法、标记--清除、标记--整理、分代收集,每种垃圾收集器可以说都是一种或多种垃圾收集算法的实现。堆空间分代、垃圾收集器、垃圾收集算法三者的关系可以用以下特点概括:
不同垃圾收集算法具备不同的特点,对于每块堆内存空间来讲都有比较符合存储对象特点的垃圾收集算法。主要介绍复制算法、标记 -- 清除、标记 -- 整理、分代收集算法
先标记 --> 再移动整合 --> 最后收集
这块内容留到G1垃圾收集器再专门介绍,简单理解就是收集器根据不同内存区域采用不同算法实现垃圾回收
根据不同垃圾收集算法实现的垃圾收集器具备不同特点,当然也就运用于不同内存区域。其中新生代垃圾收集器包括Serial、ParNew、Parallel Scavenge,老年代垃圾收集器Serial Old、Parallel Old、CMS以及分代收集器G1等。不同的垃圾收集器可以配合使用,根据不同的需求场景可以选择最合适的配合
首先需要明确G1垃圾收集器内存划分采用化整为零思想,一个个独立的Regin区域组成整个GC堆。新生代、老年代概念仅仅标识某些可以物理上不连续的Regin集合
G1收集器还有一个比较重要的特征就是可预测停顿,这点与关注吞吐量的Parallel收集器类似。即在M时间段内可设置用户垃圾回收的时长不超过N,具体实现原理就是将所有Region的垃圾收集维护一个优先级表,GC时计算出N时长内效率最高的一些Region进行回收
当某个对象位于Region1,引用该对象的对象位于Region2,那么在可达性算法分析时进行全堆扫描?G1中为每个Region维护一个Remembered Set,当其它引用对象对该某个对象对象产生引用关系时就会在引用对象的Remembered Set中记录,保证了引用关系标记的准确性
除了初始标记与并发标记与CMS一致外,G1后两个阶段为最终标记与筛选回收。筛选回收也就是根据上面讲的优先级列表进行,该阶段会STW并行执行,且回收算法带有内存整合。最终标记就是将在并发标记阶段用户线程记录到Remembered Set logs的引用关系合并到Remembered Set中,修正标记结果
垃圾收集器具备多种搭配,每种垃圾收集器又都有一些自己独特的配置。所以针对这两点,将从垃圾收集器选择参数以及收集器配置两方面讲解一些常用参数
这套垃圾收集器组合是Client模式下默认的垃圾收集器配置,若在Server模式下想强制指定该配置则使用参数 -XX:+UseSerialGC
即可。使用该组合垃圾收集器后新生代用DefNew 表示,老年代使用Tenured表示
相对于Serial来讲ParNew基本可以说是多线程版本,同时它还是出了Serial之外唯一可以与CMS合作的新生代垃圾收集器。使用参数 -XX:UseParNew
强制指定,使用ParNew垃圾收集器后新生代使用ParNew标记
关注吞吐量,JDK1.8默认的垃圾收集器组合。使用参数 +XX:UseParallelGC
强制指定,前面讲过相对于ParNew来讲,Parallel Scavenge还有最重要的特征就是堆内存分配自适应调节策略,使用参数 -XX:UseAdaptiveSizePolicy
参数打开。只需要设置最大最小堆,新生代老年代大小比例,新生代Eden、S区域比例,晋升老年代年龄等参数都会自动设置。这套组合的新生代用PSYoungGen、老年代用ParOldGen表示。当然吞吐量相关参数:
-XX:GCTimeRatio
:0-100的整数,1 / (1 + GCTimeRatio) = 垃圾回收时间占比 -XX:MaxGCPauseMillis
: GC使用最长时间,单位毫秒
使用参数 -XX:+UseConcMarkSweepGC
强制指定垃圾收集器,需要注意的是这里的Serial仅仅只是一个后备的垃圾收集器而已。当然使用CMS后老年代使用CMS表示,比较重要的一点就是CMS采用标记 -- 清除算法有可能会导致重复频繁的GC。为了控制这种情况,CMS提供参数 -XX:CMSFullGCsBeforeCompaction
指定多少次Full GC后进行一次内存整理
讲完GC大部分相关内容后总得清楚什么时候发生GC这个操作呀,首先需要明确的是GC分为新生代的Minor GC 以及 老年代的Full GC。那么这两种GC到底在什么时候触发呢?
当新生代剩余连续内存不足以分配新生对象,老年代剩余空间满足分配担保策略需求的时候会执行Minor GC,如若不然执行Full GC