什么是垃圾
在内存中不再使用的对象,而回收就是将垃圾倒掉。垃圾回收的算法有:引用计数、复制、标记压缩、分区、分代。
引用计数:核心就是对象被其他的引用计数器加1,引用失效就减1。问题:①无法处理循环引用的情况。②引用和去引用都会进行计算,比较浪费系统性能。
标记清除:标记和清除对象,弊端就是会产生垃圾碎片问题。大致的过程就是:首先从根节点出发,标记所有从根节点的可达对象,未被标记的就是需要清除的对象。对象的内存分配一定大小,但是不会直接全部回收,会产生一部分的不会被回收的问题,这样子就产生了垃圾碎片的问题。垃圾碎片可能会影响到连续内存空间的分配的。
复制算法(新生代):将内存空间分为两部分,每次只是使用一块,在垃圾回收的时候将正在使用的内存对象复制到未被使用的内存中,之后去除之前正在使用的内存中的对象,反复的交换这两个角色,总而达到清除垃圾的目的。问题:浪费空间。(新生代:eden区、s0、s1区,eden区就是刚开始实例化的对象就放在这个区域。S0和s1区就是两个内存相同、可以相互转换的区域)。
标记压缩法(老年代):在标记的基础上做了优化,把存活的对象压缩到内存一端,而后进行垃圾清理。
分代:根据对象的特定将内存分为很多的小块,而后根据每个内存的特点使用的不同的算法。
分区:将整个内存分为N个独立的空间,每个小的空间都可以独立的使用,这样的细粒度的控制一次回收都少个小空间和那些个小空间,而不是对整个空间进行GC,从而提升性能,减少GC的停顿时间。本质就是细粒度的控制GC。注意:分区和分代是不一样的,分代是分男女的,分区是不分男女的。Java的G1就是采用的分区。
STW
STOP THE WORLD,java的一种全局暂停的现象。全局停顿,所有的java代码停止,native代码可以执行,但是不能和jvm交互,多半是GC引起。危害:长时间没有响应服务,遇到HA系统,可能引起主备切换,严重危害生产环境。
收集器
- 串行收集器:serialGc,新生代、老年代使用串行回收。新生代采取复制算法,老年代采取标记-压缩算法。
- 并行收集器:ParNew(新生代并行收集器)。多线程,需要多核支持。
-
并行收集器:Parallel,类似于ParNew,新生代复制算法的,老年代默认是串行收集,但是如果要老年代也使用并行收集,那么就需要使用XX:+UseParallelOldGC。XX:+UseGCPauseMills最大停顿时间,单位为秒。XX:+GCTimeRatio垃圾收集时间占总时间的比例,默认是99,即最大允许1%时间做GC。
-
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的Java应用集中在互联网站或者B/S系统的服务端上,这类应用尤其重视服务器的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。CMS收集器就非常符合这类应用的需求
CMS收集器是基于“标记-清除”算法实现的。它的运作过程相对前面几种收集器来说更复杂一些,整个过程分为4个步骤:
(1)初始标记
(2)并发标记
(3)重新标记
(4)并发清除
其中,初始标记、重新标记这两个步骤仍然需要“Stop The World”.
CMS收集器主要优点:并发收集,低停顿。
CMS三个明显的缺点:
(1)CMS收集器对CPU资源非常敏感。CPU个数少于4个时,CMS对于用户程序的影响就可能变得很大,为了应付这种情况,虚拟机提供了一种称为“增量式并发收集器”的CMS收集器变种。所做的事情和单CPU年代PC机操作系统使用抢占式来模拟多任务机制的思想
(2)CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。在JDK1.5的默认设置下,CMS收集器当老年代使用了68%的空间后就会被激活,这是一个偏保守的设置,如果在应用中蓝年代增长不是太快,可以适当调高参数-XX:CMSInitiatingOccupancyFraction的值来提高触发百分比,以便降低内存回收次数从而获取更好的性能,在JDK1.6中,CMS收集器的启动阀值已经提升至92%。
(3)CMS是基于“标记-清除”算法实现的收集器,手机结束时会有大量空间碎片产生。空间碎片过多,可能会出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前出发FullGC。为了解决这个问题,CMS收集器提供了一个-XX:+UseCMSCompactAtFullCollection开关参数(默认就是开启的),用于在CMS收集器顶不住要进行FullGC时开启内存碎片合并整理过程,内存整理的过程是无法并发的,空间碎片问题没有了,但停顿时间变长了。虚拟机设计者还提供了另外一个参数-XX:CMSFullGCsBeforeCompaction,这个参数是用于设置执行多少次不压缩的Full GC后,跟着来一次带压缩的(默认值为0,标识每次进入Full GC时都进行碎片整理)
G1收集器
G1收集器的优势:
(1)并行与并发
(2)分代收集
(3)空间整理 (标记整理算法,复制算法)
(4)可预测的停顿(G1处处理追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内,消耗在垃圾收集上的时间不得超过N毫秒,这几乎已经实现Java(RTSJ)的来及收集器的特征)
使用G1收集器时,Java堆的内存布局是整个规划为多个大小相等的独立区域(Region),虽然还保留有新生代和老年代的概念,但新生代和老年代不再是物理隔离的了,它们都是一部分Region的集合。
G1收集器之所以能建立可预测的停顿时间模型,是因为它可以有计划地避免在真个Java堆中进行全区域的垃圾收集。G1跟踪各个Region里面的垃圾堆积的价值大小(回收所获取的空间大小以及回收所需要的时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(这也就是Garbage-First名称的又来)。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了G1收集器在有限的时间内可以获取尽量可能高的灰机效率
G1 内存“化整为零”的思路
在GC根节点的枚举范围中加入Remembered Set即可保证不对全堆扫描也不会遗漏。
如果不计算维护Remembered Set的操作,G1收集器的运作大致可划分为一下步骤:
(1)初始标记
(2)并发标记
(3)最终标记
(4)筛选回收