JVM垃圾回收——入门

142 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

jvm垃圾回收

垃圾回收的定义

垃圾回收 (Garbage Collection)是Java虚拟机 (JVM)垃圾回收器提供的一种用于在空闲时间不定时回收无任何对象引用的对象占据的内存空间的一种机制。

相关名词定义

img

1.老年代Old Generation

在新生代每进行一次垃圾回收存活的对象,对象年龄增加1岁,当对象年龄到大一定岁数后(默认是15,可以通过-XX:MaxTenuringThreshold设置),会进入老年代。

另外比较大的对象也会进入老年代,可以通过-XX:PretenureSizeThreshold进行设置,超过此大小的对象会进入老年代

2.新生代Young Generation

一般新创建的对象放在新生代(大对象除外)分为一个Eden区、与两个Survivor区

特点:存放很快就会被GC回收掉的或者不是特别大的对象

img

3.full gc / major gc

老年代GC,指的是发生在老年代的GC,出现Major GC一般经常会伴有Minor GC,Major GC的速度比Minor GC慢的多

4.minor gc

新生代GC,指的是发生在新生代的垃圾收集动作。.由于java对象大都是朝生夕死的,所以Minor GC非常频繁,一般回收速度也比较快

5.永久代Permanent Generation

即jvm的方法区,在这里存放着一些被虚拟机加载的类信息(别忘了还有动态生成的类)的静态文件,这就导致了这个区中的东西比老年代和新生代更不容易回收。

永久代大小通过-XX:MaxPermSize=进行设置。

6.元空间MetaSpace

从JDK 8开始,Java开始使用元空间取代永久代,元空间并不在虚拟机中,而是直接使用本地内存

垃圾回收的触发条件

full gc的触发条件

除了system.gc外,有以下四种:

  1. 老年代的空间不足

    老年代空间只有在新生代对象转入或创建大对象、大数组时才会出现不足,如果执行full gc后仍让出现不足,会抛出java.lang.OutOfMemoryError: Java heap space

    为了避免上述情况:应当尽量是的对象在minor gc阶段回收、让对象在新生代存活久一些以及避免大对象、大数组的创建

  2. 永久代Permanet Generation空间满

    PermanetGeneration中存放的为一些class的信息等,当系统中要加载的类、反射的类和调用的方法较多时,Permanet Generation可能会被占满,在未配置为采用CMS GC的情况下会执行Full GC。如果经过Full GC仍然回收不了,那么JVM会抛出如下错误信息: java.lang.OutOfMemoryError: PermGen space 为避免Perm Gen占满造成Full GC现象,可采用的方法为增大Perm Gen空间或转为使用CMS FGC.

  3. CMS GC时出现promotion failed和concurrent mode failure

    对于采用CMS进行旧生代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况,当这两种状况出现时可能会触发Full GC。 promotionfailed是在进行Minor GC时,survivor space放不下、对象只能放入旧生代,而此时旧生代也放不下造成的;concurrent mode failure是在执行CMS GC的过程中同时有对象要放入旧生代,而此时旧生代空间不足造成的。 应对措施为:增大survivorspace、旧生代空间或调低触发并发GC的比率,但在JDK 5.0+、6.0+的版本中有可能会由于JDK的bug29导致CMS在remark完毕后很久才触发sweeping动作。对于这种状况,可通过设置-XX:CMSMaxAbortablePrecleanTime=5(单位为ms)来避免。

  4. 统计得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间

    这是一个较为复杂的触发情况,Hotspot为了避免由于新生代对象晋升到旧生代导致旧生代空间不足的现象,在进行Minor GC时,做了一个判断,如果之前统计所得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间,那么就直接触发Full GC。 例如程序第一次触发MinorGC后,有6MB的对象晋升到旧生代,那么当下一次Minor GC发生时,首先检查旧生代的剩余空间是否大于6MB,如果小于6MB,则执行Full GC。 当新生代采用PSGC时,方式稍有不同,PS GC是在Minor GC后也会检查,例如上面的例子中第一次Minor GC后,PS GC会检查此时旧生代的剩余空间是否大于6MB,如小于,则触发对旧生代的回收。 除了以上4种状况外,对于使用RMI来进行RPC或管理的Sun JDK应用而言,默认情况下会一小时执行一次Full GC。可通过在启动时通过- java-Dsun.rmi.dgc.client.gcInterval=3600000来设置Full GC执行的间隔时间或通过-XX:+ DisableExplicitGC来禁止RMI调用System.gc。

minor gc的触发条件

jvm在进行minorGC之前会判断老年代最大的可用连续空间是否大于新生代的所有对象总空间

  1. 如果大于的话,直接执行minorGC
  2. 如果小于,判断是否开启了HandlerPromotionFailure没有直接full gc
  3. 如果开启了HandlerPromotionFailure判断老年代的最大连续内存空间是否大于历次晋升(晋级老年代对象的平均大小)平均值的大小,如果小于直接执行FullGC如果大于的话,执行minorGC