JVM垃圾回收策略浅谈

JVM垃圾回收策略浅谈 ??最近系统性的学习了java中JVM的垃圾回收策略,虽然平时写代码基本不用怎么关注JVM内部的实现机制,但是作为一个开发人员,想要成长为一个架构师级别的或者高级开发人员,那么JVM将是你必须了解的并且掌握的,我理解要知其然,更要知其所以然,好了,废话不多说,下面就谈谈JVM的垃圾回收机制,希望对大家以后的发展有所帮助。
JVM垃圾回收是靠垃圾回收器完成的,垃圾回收器必须能完成两件事情:
一、能够正确的检测出垃圾对象。
二、能否释放垃圾对象占用的内存空间。
先说说JVM如何检测垃圾对象 ??JVM中只要某个对象不再被其他活动对象引用,那么这个对象就 可以称为垃圾对象,此时的垃圾对象,就可以被JVM垃圾收集器回收了。这里要说明一下,所谓的活动对象是指能够被一个根对象集合到达的对象,如图1所示。
JVM垃圾回收策略浅谈
文章图片

图 1
图中的根对象集合主要包括一下5种元素。

  • 在方法中局部变量区的对象的引用。
  • 在java操作栈中的对象引用,有些对象时直接在操作栈中持有的,所以操作栈肯定也包含根对象集合。
  • 在常量池中的对象引用:每个类都会包含一个常量池,这些常量池中也会包含很多对象引用,如表示类名的字符串就保存在堆中,那么常量池中只会持有这个字符串对象的引用。
  • 在本地方法中持有的对象引用:有些对象被传入本地方法中,但是这些对象还没有被释放。
  • 类的Class对象:当每个类别JVM加载时都会创建一个代表这个类的唯一数据类型的Class对象,这个Class对象存在堆中,当这个类不在被使用时,在方法区中类数据和这个Class对象同样需要被回收。
??JVM在被垃圾回收时会检查堆中的所有对象是否都会被这些跟对象直接或者间接引用,能够别引用的对象就是活动对象,否则就可以被垃圾回收器回收了。
再来谈谈JVM是如何来进行垃圾回收的
JVM垃圾回收即释放被JVM垃圾回收器认定为垃圾对象所占用的内存空间。

??JVM经过这么长时间的发展,垃圾收集算法也是多种多样,每种算法各有优缺点,这里我主要说下平时用的最多的hotspot中使用的基于分代的垃圾收集方式。
??基于分代垃圾收集算法的主要原理是把对象按照寿命长短分组,分为年轻代和年老代,新创建的被分在年轻代,如果对象经过几次回收后仍然存活,那么再把这个对象划分到年老代。年老代的收集频度没有年轻代那么频繁,这样就减少了每次垃圾收集时所要扫描的对象的数量,从而提高了垃圾回收效率。
??这种设计的思路是把堆划分成若干个子堆,每个子堆对应一个年龄代,如图2所示。
JVM垃圾回收策略浅谈
文章图片

图 2
??JVM将整个堆划分为Young区、Old区和Perm区,分别存放不同年龄的对象,这三个区存放的对象有如下区别。
  • Young区又分为Eden区和两个Survivor区,其中所有新创建的对象都在Eden区,当Eden区满后会触发minor GC将Eden区仍然存活的对象复制到其中一个Survivor区中,另外一个Survivor区中的存活对象也复制到这个Survivor中,以保证始终有一个Survivor区是空的。
  • Old区存放的是Young区的Survivor满后触发minor GC后仍然存活的对象,当Eden区满后会将对象存放到Survivor区中,如果Survivor区仍然存不下这些对象,GC收集器会将这些对象直接放到Old区。如果在Survivor区中的对象足够老,也直接存放在Old区。如果Old区也满了,将会触发Full GC,回收整个堆内存。
  • Perm区存放的主要是类的Class对象,如果一个类被频繁的加载,也可能会导致Perm区满,Perm区的垃圾回收也是由Full GC触发的。
??在Sun官方提供的JDK工具包中提供了一个visualvm工具,具体位置在JDK安装目录bin下的,可以自己去搜,在visualvm有个Visual GC 插件可以观察到JVM的不同代的垃圾回收情况,如图3所示。
JVM垃圾回收策略浅谈
文章图片

图 3
??通过Visual GC插件可以观察到每个代的当前内存大小和回收次数等。Sun对堆中的不同代的大小也给出了建议,一般建议Young区的大小为整个堆的1/4,而Young区中Survivor区一般设置为整个Young区的1/8。
??GC收集器堆这些区采用的垃圾收集算法也不一样,Hotspot提供了三类垃圾收集算法,下面分别介绍下这三类垃圾收集算法的区别和使用方法。这三类垃圾收集算法分别是:
  • Serial Collector
  • ParNew Collector
  • CMS Collector
Serial Collector
??串行收集器,JVM client模式下的默认收集器,使用复制算法,在进行垃圾回收时会暂停其他所有的工作线程(stop the world,简称STW)直至回收结束,因此会影响用户的正常使用体验,但是因为少了多线程切换的开销,相较于其他收集器能够更加专注于垃圾回收,在单核场景下效率极高,并且在回收较小内存(几十或者一两百兆)时,停顿时间是毫秒级的。
【JVM垃圾回收策略浅谈】主要特点:
  • 主要针对新生代
  • 采用复制算法
  • 单线程收集
  • 进行垃圾收集时,必须暂停所有工作线程,直到完成
Serial/Serial Old组合收集器运行示意图如图4所示
JVM垃圾回收策略浅谈
文章图片

图 4 应用场景
  • HotSpot在Client模式下默认的新生代收集器;
  • 简单高效(与其他收集器的单线程相比)
  • 对于限定单个CPU的环境来说,Serial收集器没有线程交互(切换)开销,可以获得最高的单线程收集效率
  • 在用户的桌面应用场景中,可用内存一般不大(几十M至一两百M),可以在较短时间内完成垃圾收集(几十MS至一百多MS),只要不频繁发生,这是可以接受的
ParNew Collector
ParNew垃圾收集器是Serial收集器的多线程版本。
主要特点
?? 除了多线程外,其余的行为、特点和Serial收集器一样,如Serial收集器可用控制参数、收集算法、Stop The World、内存分配规则、回收策略等,两个收集器共用了不少代码。
ParNew/Serial Old组合收集器运行示意图如图5:
JVM垃圾回收策略浅谈
文章图片

图 5 应用场景
??在Server模式下,ParNew收集器是一个非常重要的收集器,因为除Serial外,目前只有它能与CMS收集器配合工作,但在单个CPU环境中,不会比Serail收集器有更好的效果,因为存在线程交互开销。
CMS Collector
??并发标记清理(Concurrent Mark Sweep,CMS)收集器也称为并发低停顿收集器(Concurrent Low Pause Collector)或低延迟(low-latency)垃圾收集器。
特点
  • 针对老年代
  • 基于"标记-清除"算法(不进行压缩操作,产生内存碎片)
  • 以获取最短回收停顿时间为目标
  • 并发收集、低停顿
  • 需要更多的内存
是HotSpot在JDK1.5推出的第一款真正意义上的并发(Concurrent)收集器,第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。
CMS收集器运行示意图如下:
JVM垃圾回收策略浅谈
文章图片

图 6 应用场景
??与用户交互较多的场景,希望系统停顿时间最短,注重服务的响应速度,以给用户带来较好的体验,如常见WEB、B/S系统的服务器上的应用。
以上就是关于JVM垃圾回收机制的大致了解,以后还需要更加深入的学习。

    推荐阅读