一、垃圾回收的作用
java的一大特点就是自动垃圾回收处理机制,无需开发人员过度关注系统内存资源的释放,减轻开发者的工作量,同时也避免了由于内存无法释放而导致程序内存溢出宕掉的危机。选择一个合理的垃圾回收策略至关重要。
垃圾回收(GC)主要关注3个问题
1、那些对象需要回收?
2、什么时候回收?
3、如何回收?
二、垃圾回收算法
1、引用计数法(Reference Counting)
原理:使用计数器标记某对象被其他对象引用的个数,计数器为0时表示该对象未被引用,方可回收。
弊端:无法处理循环引用。对于对象A引用B,C也引用B,B的计数为2,当AC不再应用B时,计数为0释放B;但如果AB相互引用,系统中也不存在第三个对象引用A或B,此时AB均应该被回收,但双方计数器都不为0,所以无法应对循环引用对象的回收。
2、标记-清除法(Mark-Sweep)
原理:将回收分为2各阶段:标记阶段、清除阶段;从某个根对象开始,将所有引用可达的对象标记为存活对象,不可达的对象标记为垃圾对象,在清除阶段被清除;
弊端:由于存活对象的的存放不是连续的,回收后的空间并不连续,容易产生大量空间碎片,对大对象的内存分配效率降低
3、复制算法(Copying)
原理:将内存空间分程2快,每次只使用其中一块,回收时,将正在使用的存活对象全部复制到另一块内存空间,剩下的未使用对象全部回收。既没有碎片,又高效。
弊端:仅适用于垃圾对象远多于存活对象(新生代),否则复制的消耗颇大。
4、标记-压缩算法(Mark-Compact)
原理:跟标记-清除法类似,从根节点开始查找可达引用对象,标记完成后,将未标记对象压缩到内存另一端,再清除;避免产生大量空间碎片。性价比颇高。
5、增量算法(Incremental Collection)
原理:如果一次性将所有的垃圾对象回收,会造成系统长时间停顿;那么将回收线程和应用程序线程交替执行,每次只回收一小片区域的内存空间,切换到应用程序线程,如此反复,直到垃圾回收完毕。
弊端:回收成本总体上升,系统吞吐量下降。
6、分代(Generational Collecting)——应用最广泛
原理:合百家之长,根据对象特点将内存分块,每块使用不同的回收算法提高回收效率。
以hotspot为例,对于年轻代(存放刚创建出的对象的内存区域),年轻代的特点就是朝生夕灭,故采用回收效率较高的复制算法;对于几经回收还没被kill的老老年代区域,使用标记-压缩算法
三、垃圾回收评价指标
判断一个垃圾处理器好坏,可有以下几个指标
1、吞吐量
应用程序处理时间/系统总运行时间。系统运行100min,GC耗时2min,此时系统吞吐量=(100-2)/100=98%,吞吐量标志着程序的执行效率。
2、停顿时间
GC正在执行时,应用程序暂停的时间。
3、垃圾回收频率
GC多长时间执行一次,一般来说,对于固定的应用程序,GC 执行频率越低越好,避免造成程序的停顿时间。
4、反应时间
一个对象成为垃圾后,多长时间释放它所占据的内存空间。
5、总结
通常情况需要根据程序特点综合考量上述指标,例如对客户端程序应尽量减少停顿时间,保证良好的用户体验,为此得牺牲GC的吞吐量;对于后台服务而言,则应尽量增加GC吞吐量,可适当的延迟系统停顿时间。
四、垃圾回收器类型
1、串行收集器
使用单线程执行GC的独占式垃圾回收方式。
1)特点
在串行收集器进行GC时,所有的java线程都需要暂停,等待GC完成,这种所有应用程序线程暂停等待系统GC的现象叫做“Stop the World”,这种方式程序停顿时间长,造成系统假死,在实时性要求高的系统中不适用。
但也不能忽略它长期的实战能力,大多数情况下,串行垃圾回收器还是不错的。
2)种类
新生代串行收集器
采用复制算法,实现简单高效,单线程GC操作,故没有线程切换的开销,它是HotSpot中JVM在客户端模式下运行默认的垃圾回收器
老年代串行收集器
采用标记-压缩算法,由于老年代的GC通常比新生代长,所以在堆空间较大的程序中,老年代串行收集器一启动,应用程序停顿时间会更长。
2、并行收集器
多线程执行GC的独占式回收方式
1)特点
在并行收集器进行GC时,所有的java线程也需要暂停,等待GC完成,但由于多线程并行执行GC,所有系统等待停顿时间会比串行短,同时系统吞吐量增加。考虑到多线程的并发操作资源消耗,对于单CPU处理并发能力差的系统中,不适用。
2)种类
新生代并行收集器
尤其关注系统吞吐量,可使用两个参数-XX:MaxGCPauseMillis(设置最大GC停顿时间)、-XX:GCTimeRatio(设置吞吐量,从0~100之间的整数)
老年代并行收集器
采用标记-压缩算法,在JDK1.6版本以后投入使用。
3、CMS收集器
同并行收集器关注吞吐量不同,CMS主要关注系统停顿时间。
4、G1收集器
目前最新的垃圾回收器,采用压缩-标记算法,在吞吐量和停顿上都得到控制,优于CMS。
五、总结
1、停顿现象
在进行GC时,会造成应用程序的卡顿假死,当生产环境遇到问题,莫名其妙的停止工作,可以检查是否有GC引起。
2、GC收集器的合理选择和参数配置
对于软件系统的性能而言,收集器的选择至关重要,可也综合使用多个收集器进行应用,并配置相关参数进行GC控制。