最近系统性的学习了java中JVM的垃圾回收策略,虽然平时写代码基本不用怎么关注JVM内部的实现机制,但是作为一个开发人员,想要成长为一个架构师级别的或者高级开发人员,那么JVM将是你必须了解的并且掌握的,我理解要知其然,更要知其所以然,好了,废话不多说,下面就谈谈JVM的垃圾回收机制,希望对大家以后的发展有所帮助。
JVM垃圾回收是靠垃圾回收器完成的,垃圾回收器必须能完成两件事情:
一、能够正确的检测出垃圾对象。
二、能否释放垃圾对象占用的内存空间。
JVM中只要某个对象不再被其他活动对象引用,那么这个对象就 可以称为垃圾对象,此时的垃圾对象,就可以被JVM垃圾收集器回收了。这里要说明一下,所谓的活动对象是指能够被一个根对象集合到达的对象,如图1所示。
JVM在被垃圾回收时会检查堆中的所有对象是否都会被这些跟对象直接或者间接引用,能够别引用的对象就是活动对象,否则就可以被垃圾回收器回收了。
JVM垃圾回收即释放被JVM垃圾回收器认定为垃圾对象所占用的内存空间。
JVM经过这么长时间的发展,垃圾收集算法也是多种多样,每种算法各有优缺点,这里我主要说下平时用的最多的hotspot中使用的基于分代的垃圾收集方式。
基于分代垃圾收集算法的主要原理是把对象按照寿命长短分组,分为年轻代和年老代,新创建的被分在年轻代,如果对象经过几次回收后仍然存活,那么再把这个对象划分到年老代。年老代的收集频度没有年轻代那么频繁,这样就减少了每次垃圾收集时所要扫描的对象的数量,从而提高了垃圾回收效率。
这种设计的思路是把堆划分成若干个子堆,每个子堆对应一个年龄代,如图2所示。
JVM将整个堆划分为Young区、Old区和Perm区,分别存放不同年龄的对象,这三个区存放的对象有如下区别。
在Sun官方提供的JDK工具包中提供了一个visualvm工具,具体位置在JDK安装目录bin下的,可以自己去搜,在visualvm有个Visual GC 插件可以观察到JVM的不同代的垃圾回收情况,如图3所示。
通过Visual GC插件可以观察到每个代的当前内存大小和回收次数等。Sun对堆中的不同代的大小也给出了建议,一般建议Young区的大小为整个堆的1/4,而Young区中Survivor区一般设置为整个Young区的1/8。
GC收集器堆这些区采用的垃圾收集算法也不一样,Hotspot提供了三类垃圾收集算法,下面分别介绍下这三类垃圾收集算法的区别和使用方法。这三类垃圾收集算法分别是:
串行收集器,JVM client模式下的默认收集器,使用复制算法,在进行垃圾回收时会暂停其他所有的工作线程(stop the world,简称STW)直至回收结束,因此会影响用户的正常使用体验,但是因为少了多线程切换的开销,相较于其他收集器能够更加专注于垃圾回收,在单核场景下效率极高,并且在回收较小内存(几十或者一两百兆)时,停顿时间是毫秒级的。
主要特点:
Serial/Serial Old组合收集器运行示意图如图4所示
应用场景
ParNew垃圾收集器是Serial收集器的多线程版本。
主要特点
除了多线程外,其余的行为、特点和Serial收集器一样,如Serial收集器可用控制参数、收集算法、Stop The World、内存分配规则、回收策略等,两个收集器共用了不少代码。
ParNew/Serial Old组合收集器运行示意图如图5:
应用场景
在Server模式下,ParNew收集器是一个非常重要的收集器,因为除Serial外,目前只有它能与CMS收集器配合工作,但在单个CPU环境中,不会比Serail收集器有更好的效果,因为存在线程交互开销。
并发标记清理(Concurrent Mark Sweep,CMS)收集器也称为并发低停顿收集器(Concurrent Low Pause Collector)或低延迟(low-latency)垃圾收集器。
特点
是HotSpot在JDK1.5推出的第一款真正意义上的并发(Concurrent)收集器,第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。
CMS收集器运行示意图如下:
应用场景
与用户交互较多的场景,希望系统停顿时间最短,注重服务的响应速度,以给用户带来较好的体验,如常见WEB、B/S系统的服务器上的应用。
以上就是关于JVM垃圾回收机制的大致了解,以后还需要更加深入的学习。