在谈垃圾收集器前先简单的大致了解下垃圾收集算法
1. 标记清除算法
就是先标记需要回收的对象,然后统一回收所标记对象。
缺点:产生大量不连续的内存碎片,空间碎片太多可能会导致后期JVM需要分配大对象时,无法找到足够连续内存空间,而再次触发一次垃圾收集动作。
2. 复制算法
需要两块内存空间,只使用其中一块。开始回收的时候将已使用的一块内存空间中存活对象复制到另一块内存空间,并一次性回收这块内存空间。
缺点:会有一定的内存空间浪费
3. 标记-整理算法
有点像是整合了标记清除算法和复制算法。标记可回收对象,然后复制所有存活对象像一端移动。最后直接清理掉边界外的内存。
4. 分代收集算法
内存区域根据对象存活周期划分为几块。新生代和老年代。新生代只有少量存活对象,使用复制算法。老年代因为对象存活率较高,使用标记清理或者标记整理算法。
不同的垃圾收集器
1. Serial收集器
新生代收集器,历史悠久的垃圾收集器,曾经是JDK1.3.1之前新生代收集的唯一选择。
是一个单线程的收集器,需要暂停其他所有工作线程(用户操作线程也需要一并停止),直到垃圾收集的结束。
client模式下默认
学习来源:《深入理解Java虚拟机》-- JDK1.7
2. ParNew收集器
新生代收集器,其实就是Serial收集器的多线程版本。在单CPU环境中不会比Serial收集器有更好的效果。
默认开启线程数量与CPU数量相同,也可以使用-XX:ParalledGCThreads配置线程数量。
server模式下首选
学习来源:《深入理解Java虚拟机》-- JDK1.7
3. Parallel Scavenge收集器
新生代收集器,使用复制算法,多线程收集器(与Serial和ParNew一样需要暂停所有其他线程),
可控吞吐量的垃圾收集器。
吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)。
1)-XX:MaxGCPauseMillis参与值是一个大于0的毫秒数。收集器尽可能的保证内存回收花费时间不超过设定值。
(JDK11默认值200)
2)-XX:GCTimeRatio参数值是一个大于0且小于100的整数。用来配置垃圾收集时间占总时间的比率,相当于是吞吐量的倒数。(1/1+N)
例如:-XX:GCTimeRatio=19
1/(1+19)=0.05。即5%。
书中所写默认值为99
(JDK11默认值12)
3)-XX:UseAdaptiveSizePolicy开关参数。默认开启。开关打开后就不需要手工指定新生代的大小(-Xmm)、Eden与Servivor区的比例(-XX:SurvivorRatio)、晋升老年代对象年龄(-XX:PretenureSizeThreshold)等细节参数。虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量,这种调节方式成为GC自适应的调剂策略。这也是Parallel Scavenge收集器与ParNew收集器的一个重要区别。
(JDK 1.8 默认使用 UseParallelGC 垃圾回收器,该垃圾回收器默认启动了 AdaptiveSizePolicy)
无法与CMS配合使用。
学习来源:《深入理解Java虚拟机》-- JDK1.7
4. Serial Old收集器
Serial收集器的老年代版本。采用标记整理算法。
主要在client模式下使用。
如果在server模式下有两大用途。一种是在JDK1.5以及之前的版本中与Parallel Scavenge收集器搭配使用。另一种用途就是作为CMS收集器的后备预案,在并发收集发生Conncurrent Mode Failure时使用。
5. Paralled Old收集器
6. CMS收集器
7. G1收集器
111