垃圾回收器:
Serial收集器:
采用复制算法,是一种单线程的垃圾回收机制,是虚拟机新生代默认情况下的首选收集器。
特点:与其他单线程收集器相比,简单而高效。但是因为在垃圾回收过程中要中断别的工作线程。
Parnew收集器:
Serial收集器的多线程版本,是Server端模式下虚拟机的首选的新生代收集器。
目前只有它能与CMS收集器(第一个真正意义上的并发收集器)进行配合使用。
Parallel Scavenge收集器:
使用的是复制算法,并行的多线程新生代收集器,这个收集器的关注点是:吞吐量,
即 吞吐量=用户代码所占用CUP时间/(用户代码所占用的CUP时间+垃圾回收所占用的CPU时间)。
由于关注的是吞吐量,此垃圾收集器主要用于后台运算量较大交互较少的虚拟机。
SerialOld收集器:
是Serial收集器的老年代版本,他是一个单线程的收集器,使用"标记——整理算法"实现。主要是在Client模式下进行使用,如果在Server模式下有两大用途:
1.配合Parallel Scavenge收集器使用
2.可以作为CMS收集器的备选预案,在Concurren Mark Sweap 下使用。
ParallelOld收集器:
是ParallelScavenge的老年代版本,使用多线程的“标记——整理算法”,在JDK1.6之前,如果新生代使用了Parallel Scavenge收集器,老年代只能使用SerialOld收集器。
CMS收集器:
CMS收集器是一种以获取最短回收停顿时间为目标的收集器,因为现在很大一部分应用是部署在B/S服务器上,
追求的是响应速度,所以这一回收器主要用在Server端,主要实现的是“标记——清除算法”。
CMS收集器回收垃圾的过程可以分为一下四个步骤:
1.初始标记,
2.并发标记,
3.重新标记,
4.并发清除。
其中初始标记和并发标记阶段仍会短暂的暂停业务线程,
初始标记阶段仅仅是进行标记GC Roots能直接关联的对象,速度很快。
并发标记阶段就是进行GC Roots Tracing的过程,
重新标记就是为了重新修正并发标记的过程因程序变动导致标记产生变动的那一部分对象。这个阶段比初始标记稍长的一点,远
远小于并发标记。
CMS收集器的优点:并发收集,低停顿。
缺点:
1. CMS收集器对CPU资源非常敏感,面向并发设计的程序对CPU资源都比较敏感。
在进行并发阶段,回收线程虽然不会停顿程序但是会占用一部分线程(CPU资源),从而导致程序变慢,降低程序的吞吐量,
CMS默认开启的回收线程是(CPU数量+3)/4,也就是在CUP数量超过四个时,回收线程占用CPU资源25%不到,但是当CPU小
于4个时,如果CPU负载本来就比较大时,可能会导致吞吐量降低到50% 一下,这就让人忍受不了了。
为了解决这个问题虚拟机就提供了一种叫做“增量式并发收集器"(Incremental Concurrent Mark Sweap)——iCMS的CMS收集
器的变种,即在垃圾回收线程工作时,不在单独占用CPU时间,而是让业务线程和回收线程抢占CPU时间片 从而让GC线程和用户
线程交替运行, 但是目前版本中“iCMS”已被列为deprecated,不建议再使用。
2.CMS无法处理浮动垃圾
CMS垃圾回收的时候,业务线程也会执行,这个时候业务线程产生的垃圾叫做浮动垃圾(Float garbage)。
所以就导致了要预留一部分内存给浮动垃圾,这就导致了有可能内存使用率才到68%就要启动垃圾回收程序,要是预留的内存
不足,则会出现Concurrent Mode Failure,然后就会启动备用的收集器SerialOld收集器。
3.会出现内存碎片,
CMS是基于“标记——清除算法”,“标记——清除算法”的缺点就是会出现碎片,导致可用的内存空间不连续。导致无法为
占用内存较大的对象进行分配内存。
G1收集器:
相比于CMS收集器有了比较明显的改进:
1.采用"标记——清理算法",不会出现内存碎片。
2.是他能非常精确地控制停顿,既能让使用者明确指定在一个M毫秒的时间内,消耗在垃圾收集的时间不能超过N毫秒,这几乎是实时JAVA(RTSJ)垃圾收集器的特征。
G1收集器可以在基本不牺牲吞吐量的情况下完成低停顿的内存回收,这是由于它能够极力地避免全区域的垃圾收集,之前的整个垃圾收集进行的范围是整个新生代或者老年代,而G1将整个JAVA堆(包括新生代和老年代)划分为多个大小固定独立的区域,并且跟踪这些区域里面垃圾的堆积程度,在后台维护一个优先级列表,然后在允许的垃圾回收时间内,优先回收垃圾堆积最多的内存区域(Garage First的由来),区域的划分和优先级的区域回收,保证了G1收集器在有限的时间内可以获得最高的收集效率。
垃圾收集的相关参数可以自行进行百度。
查看正在使用的垃圾回收器是什么:java -XX:+PrintCommandLineFlags -version
显示正在使用的是ParallelGC
垃圾回收器配置
配置 | 描述 |
---|---|
-XX:+UseSerialGC | 串行垃圾回收器 |
-XX:+UseParallelGC | 并行垃圾回收器 |
-XX:+UseConcMarkSweepGC | 并发标记扫描垃圾回收器 |
-XX:ParallelCMSThreads= | 并发标记扫描垃圾回收器 =为使用的线程数量 |
-XX:+UseG1GC | G1垃圾回收器 |
检测指定的垃圾回收器是否生效:jmap -heap pid (所起服务的进程ID)
垃圾回收日志打印:-XX:+PrintGCDetails 输出GC的详细日志
日志信息详细解释:
[GC (System.gc()) [PSYoungGen: 19712K->760K(38400K)] 19712K->768K(125952K), 0.0013102 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[Full GC (System.gc()) [PSYoungGen: 760K->0K(38400K)] [ParOldGen: 8K->648K(87552K)] 768K->648K(125952K), [Metaspace: 3441K->3441K(1056768K)], 0.0063051 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
Heap
PSYoungGen total 38400K, used 333K [0x00000000d5c00000, 0x00000000d8680000, 0x0000000100000000)
eden space 33280K, 1% used [0x00000000d5c00000,0x00000000d5c534a8,0x00000000d7c80000)
from space 5120K, 0% used [0x00000000d7c80000,0x00000000d7c80000,0x00000000d8180000)
to space 5120K, 0% used [0x00000000d8180000,0x00000000d8180000,0x00000000d8680000)
ParOldGen total 87552K, used 648K [0x0000000081400000, 0x0000000086980000, 0x00000000d5c00000)
object space 87552K, 0% used [0x0000000081400000,0x00000000814a2368,0x0000000086980000)
Metaspace used 3447K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 376K, capacity 388K, committed 512K, reserved 1048576K
GC 日志开头的“[GC”和“[Full GC”说明了这次垃圾收集的停顿类型,而不是用来区 分新生代GC还是老年代GC的。如果有“Full”,说明这次GC是发生了Stop-The-World的,例如下面这段新生代收集器ParNew的日志也会出现“[Full GC”(这一般是因为出现了分配 担保失败之类的问题 .所以才导致STW)。如果是调用System.gc()方法所触发的收集,那么在这里将显示“[Full GC (System)”。
[Full GC 283.736: [ParNew: 261599K->261599K(261952K), 0.0000288 secs]接下来的“[DefNew”、“[Tenured”、“[Perm”表示GC发生的区域,这里显示的区域名称与使用的GC收集器是密切相关的,例如上面样例所使用的Serial收集器中的新生代名为“Default New Generation”,所以显示的是“[DefNew”。如果是ParNew收集器,新生代名称就会变为 “[ParNew”,意为 “Parallel New Generation”。如果采用 Parallel Scavenge 收集器,那它配套的新生代称为“PSYoungGen”,老年代和永久代同理,名称也是由收集器决定的。
后面方括号内部的19712K->760K(38400K)含义是“GC前该内存区域已使用容量- >GC后该内存区域已使用容量 (该内存区域总容董)”。而在方括号之外的19712K->768K(125952K)表示GC前Java堆已使用容量->表示GC后Java堆已使用容量(ava堆总容量)
再往后0.0063051 secs 表示该内存区域GC所占用的时间,单位是秒。[Times: user=0.01 sys=0.00, real=0.01 secs] 中的user – Total CPU time that was consumed by Garbage Collector threads during this collection
sys – Time spent in OS calls or waiting for system event
real – Clock time for which your application was stopped. With Parallel GC this number should be close to (user time + system time) divided by the number of threads used by the Garbage Collector. In this particular case 8 threads were used. Note that due to some activities not being parallelizable, it always exceeds the ratio by a certain amount