垃圾收集算法:
1、标记-清除算法:分为“标记”和“清除”两个阶段,首先标记完所有可回收对象,等待标记完成会后开始统一清除被标记对象,有连个问题:一是效率不高,而是会产生很多不连续空间
1.1、标记算法:
1)引用计数算法
给对象添加一个计数器,每当有一个地方引用它时就加1,当引用失效时则减1,任何时刻该计数器值为0时,则表示没有任何对象引用,标记为可回收。
2)可达性分析算法
这个算法的基本思路是:通过一系列称为“GC Roots”的对象作为起始点,从这个节点开始向下搜索,搜索所走过的路径称为“引用链(ReferenceChain)”,当一个对象到GC Roots没有任何引用链相连的时候,
证明此对象不可用;
3)在java语言中,可作为GC Roots对象包括以下几种:
虚拟机栈(栈帧中的本地变量表)中引用的对象;
方法区中类静态属性引用的对象;
方法区中常量引用的对象;
本地方法栈中JNI(一般指Native方法)引用的对象;
4)Java1.2之后,对引用进行了扩充,将引用分为:
强引用(Strong Reference)
软引用(Soft Reference)
弱引用(Weak Reference)
虚引用(Phantom Reference)
GC收集器的研发进程(从上至下):
1、Serial
2、Serial Old收集器
3、Parallel Scavenge收集器
4、CMS收集器
5、garbage first收集器(G1)
垃圾收集器
1、Serial垃圾收集器
1.1、Serial收集器是最基本,历史最悠久的收集器,是jdk1.3.1之前唯一的新生代收集器;
1.2、Serial收集器是一个单线程的收集器,不仅仅只会使用一个CPU和一条线程去执行内存垃圾收集工作,并且在收集时,必须暂停所有用户线程,等待收集完成结束后,唤醒所有用户线程。
1.3、Serail收集器是java虚拟机Client模式下的默认收集器
2、ParNew垃圾收集器
2.1、ParNew收集器是Serial收集器的多线程版本,也是使用复制算法;
2.2、ParNew收集器在垃圾收集过程中,必须暂停所有线程;
2.3、ParNew收集器会开启与CPU数量相同的线程数,可以通过-XX:ParallelGCThreads参数来限制开启的线程数;
2.4、ParNew收集器是java虚拟机在server模式下默认的新生代收集器
3、ParallelScavenge收集器
3.1、ParallelScavenge收集器是一个多线程的,新生代的,采用复制算法的垃圾收集器;
3.2、Parallel Scavenge收集器关注的重点是:达到一个可控制的吞吐量(Throughput['θruːpʊt] 生产力,生产能力)
3.3、Throughput(吞吐量)=运行用户代码时间/(运行用户代码时间+垃圾收集时间)
3.4、ParallelScavenge使用参数用于精准控制吞吐量:
-XX:MaxGCPauseMillis:控制最大垃圾收集停顿时间,是一个大于0的毫秒数
-XX:GCTimeRation:直接设置吞吐量大小,是一个大于0小于100的整数,也就是程序运行时间占总时间的比率,默认值是99,即垃圾收集运行最大
-XX:+UseAdaptiveSizePolicy
这是个开关参数,打开之后就不需要手动指定新生代大小(-Xmn)、Eden与Survivor区的比例(-XX:SurvivorRation)、新生代晋升年老代对象年龄(-XX:PretenureSizeThreshold)等细节参数,虚拟机会根据当前系统运行情况收集性能监控信息,动态调整这些参数以达到最大吞吐量,这种方式称为GC自适应调节策略,自适应调节策略也是ParallelScavenge收集器与ParNew收集器的一个重要区别
4、Serial Old收集器
4.1、Serial Old收集器是Serial垃圾收集器老年代版本,
4.2、单线程收集器,垃圾收集过程中需要暂停所有用户线程;
4.3、采用标记-整理算法;
4.4、在Client模式下,是java虚拟机默认的老年代垃圾收集器;
4.5、在server模式下,主要有两个用途:
在jdk1.5之前,和ParallelScavenge收集器搭配使用;
作为老年代中使用CMS收集器的后备收集方案。
5、Parallel Old收集器
5.1、Parallel Old收集器是ParallelScavenge收集器的老年代版本;
5.2、是一个多线程收集器;
5.3、采用标记--整理算法,在jdk1.6才开始使用;
6、CMS收集器
6.1、Concurrent marksweep (CMS)是老年代垃圾收集器;
6.2、使用多线程标记--清除算法;
6.3、主要目标:获取最短垃圾回收停顿时间;
最短垃圾回收停顿时间,可以为交互比较高的程序提高用户体验;
CMS收集器是Sun Hotspot虚拟机中第一款真正意义商并发垃圾收集器;
它第一次实现垃圾收集线程与用户线程同事工作。
6.4、CMS工作机制相比其他的垃圾收集器来说更复杂,整个过程分为以下4个阶段:
a.初始标记:只是标记一下GCRoots能直接关联的对象,速度很快,仍然需要暂停所有的工作线程。
b.并发标记:进行GCRoots跟踪的过程,和用户线程一起工作,不需要暂停工作线程。
c.重新标记:为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,仍然需要暂停所有的工作线程。
d.并发清除:清除GCRoots不可达对象,和用户线程一起工作,不需要暂停工作线程。
由于耗时最长的并发标记和并发清除过程中,垃圾收集线程可以和用户现在一起并发工作,所以总体上来看CMS收集器的内存回收和用户线程是一起并发地执行。
6.5、CMS收集器有以下三个不足
1)CMS收集器对CPU资源非常敏感,其默认启动的收集线程数=(CPU数量+3)/4,在用户程序本来CPU负荷已经比较高的情况下,如果还要分出CPU资源用来运行垃圾收集器线程,会使得CPU负载加重。
2)CMS无法处理浮动垃圾(FloatingGarbage),可能会导致Concurrent ModeFailure失败而导致另一次FullGC。由于CMS收集器和用户线程并发运行,因此在收集过程中不断有新的垃圾产生,这些垃圾出现在标记过程之后,CMS无法在本次收集中处理掉它们,只好等待下一次GC时再将其清理掉,这些垃圾就称为浮动垃圾。CMS垃圾收集器不能像其他垃圾收集器那样等待年老代机会完全被填满之后再进行收集,需要预留一部分空间供并发收集时的使用,可以通过参数-XX:CMSInitiatingOccupancyFraction来设置年老代空间达到多少的百分比时触发CMS进行垃圾收集,默认是68%。
如果在CMS运行期间,预留的内存无法满足程序需要,就会出现一次ConcurrentModeFailure失败,此时虚拟机将启动预备方案,使用Serial Old收集器重新进行年老代垃圾回收。
3)CMS收集器是基于标记-清除算法,因此不可避免会产生大量不连续的内存碎片,如果无法找到一块足够大的连续内存存放对象时,将会触发因此FullGC。CMS提供一个开关参数-XX:+UseCMSCompactAtFullCollection,用于指定在FullGC之后进行内存整理,内存整理会使得垃圾收集停顿时间变长,CMS提供了另外一个参数-XX:CMSFullGCsBeforeCompaction,用于设置在执行多少次不压缩的FullGC之后,跟着再来一次内存整理。
6.6、设置参数
-XX:CMSInitiatingOccupancyFraction | 设置年老代空间达到多少的百分比时触发CMS进行垃圾收集,默认是68% |
|
-XX:+UseCMSCompactAtFullCollection | 指定在Full GC之后进行内存整理(内存整理会使得垃圾收集停顿时间变长) |
|
-XX:CMSFullGCsBeforeCompaction | 设置在执行多少次不压缩的Full GC之后,跟着再来一次内存整理,默认是:0 |
|
7、G1收集器
7.1、Garbage First垃圾收集器是目前垃圾收集器理论发展的最前沿成果;
7.2、与CMS相比,有两个突出特点:
1)基本标记--整理算法,不产生内存碎片;
2)可以非常精准控制停顿时间,在不牺牲吞吐量的前提下,实现低停顿回收。
7.3、G1垃圾收集器避免全区域垃圾收集,将堆内存划分为大小固定的几个独立区域,并且跟踪这几个独立区域的垃圾收集进度,同时后台维护一个优先级列表,每次根据所允许的收集时间,优先回收垃圾最多的区域。
7.4、区域划分和优先级回收机制,是G1收集器可以在有限时间内获得最高的垃圾回收效率。
8、java虚拟机常用的垃圾收集器配置参数:
参数 | 描述 |
UseSerialGC | 虚拟机运行在Client模式的默认值,打开此开关参数后, 使用Serial+Serial Old收集器组合进行垃圾收集。 |
UseParNewGC | 打开此开关参数后,使用ParNew+Serial Old收集器组合进 行垃圾收集。 |
UseConcMarkSweepGC | 打开此开关参数后,使用ParNew+CMS+Serial Old收集器组 合进行垃圾收集。Serial Old作为CMS收集器出现Concurrent Mode Failure的备用垃圾收集器。 |
UseParallelGC | 虚拟机运行在Server模式的默认值,打开此开关参数后, 使用Parallel Scavenge+Serial Old收集器组合进行垃圾收集。 |
UseParallelOldGC | 打开此开关参数后, 使用Parallel Scavenge+Parallel Old收集器组合进行垃圾收集。 |
SurvivorRation | 新生代内存中Eden区域与Survivor区域容量比值,默认是8,即 Eden:Survivor=8:1. |
PretenureSizeThreshold | 直接晋升到年老代的对象大小,设置此参数后,超过该大小的 对象直接在年老代中分配内存。 |
MaxTenuringThreshold | 直接晋升到年老代的对象年龄,每个对象在一次Minor GC之后还 存活,则年龄加1,当年龄超过该值时进入年老代。 |
UseAdaptiveSizePolicy | java虚拟机动态自适应策略,动态调整年老代对象年龄和各个区域大小。 |
HandlePromotionFailure | 是否允许担保分配内存失败,即整个年老代空间不足,而整个新生代中Eden和Survivor对象都存活的极端情况。 |
ParallelGCThreads | 设置并行GC时进行内存回收的线程数。 |
GCTimeRation | Parallel Scavenge收集器运行时间占总时间比率。 |
MaxGCPauseMillis | Parallel Scavenge收集器最大GC停顿时间。 |
CMSInitiatingOccupancyFraction | 设置CMS收集器在年老代空间被使用多少百分比之后触发垃圾收集,默认是68%。 |
UseCMSCompactAtFullCollection | 设置CMS收集器在完成垃圾收集之后是否进行一次内存整理。 |
CMSFullGCsBeforeCompaction | 设置CMS收集器在进行多少次垃圾收集之后才进行一次内存整理。 |
|
|
java虚拟机的-XX:+PrintGCDetails参数可以打印垃圾收集器的日志信息。
-verbose:gc可以查看Java虚拟机垃圾收集结果。