jvm中分代垃圾回收和触发垃圾回收

来源:互联网 发布:linux查看文件多大命令 编辑:程序博客网 时间:2024/05/14 08:32

   

    如图所示,在HotSpot虚拟机中共划分有三个代:年轻代(young generation),年老代(old generation)和持久代(permanent generation)。实际上真正有意义的是年轻代和年老代,对象的生成与消亡都发生在这两个区域。


    持久代(permanent generation)

    在开始介绍年轻代和年老代之前,先来说一说持久代吧。

    持久代的主要作用是存放java类等静态化的信息,可以看作是方法区的一部分。垃圾回收对持久代的影响并不大,只有某些需要动态生成类的应用才需要去关注这个区域的大小,可以通过-XX:MaxPermSize=<N>进行设置

    持久代是个比较神奇的概念,应该是Hotspot虚拟机里所特有的一个代。它是方法区的一部分,按常理不应该属于堆。并且在通过jvm参数设定各个区域大小的时候,可以很明显的发现持久代和堆的大小是需要分别指定的,两者不是一个整体。但是网络上铺天盖地的资料里都把它归属于堆,对此我一直感到无法理解,一种可能的解释是在早期的Hotspot虚拟机中,持久代就是堆的一部分。如果有高人清楚这么归类的原因,还望解惑。


    年轻代(young generation)

    年轻代是JVM堆中最常发生垃圾回收的区域,所有对象都生成于此。

    如上图所示,年轻代一般可以分成三个区域,其中一个是Eden区,另外的两个From和To都是Survivor区。一般新生成的对象都出现在Eden区,当Eden区被填满时,所有经过垃圾回收还存活的对象将被复制到两个Survivor区域中的一个,我们假定是From区(两个区域实际上没有任何区别,From和To只是为了更好的说明工作流程),当From区域也被填满时,这个区域经过垃圾回收仍存活的对象将会被复制进入To区域,原From区域被清空,并且从Eden区过来的数据将直接进入To区域。当To区域也被填满时,之前从From区域过来的那部分数据如果仍在活动,则将被放入年老代。

    需要注意的是,两个Survivor区域总有一个会是空的,并且Survivor是可以被设置为多个的。Survivor的个数越多,则对象在进入年老区之前要经历的垃圾回收次数也越多。

简单明了的说法所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分三个区。一个Eden区,两个Survivor(一般而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。

    年老代(old generation)

    在年轻代中经历多次垃圾回收后仍旧存活的对象,都将进入年老代。这个区域中的对象生命周期较长,当这个区域也被写满时,会触发整个堆的垃圾回收。


    堆的垃圾回收

    堆的垃圾回收一般被分成两种,分别是Scavenge(minor) GC 和 Full GC。

    Scavenge GC只发生在年轻代,当Eden区域的空间被写满时触发,触发后执行的动作就是发生在年轻代中的故事,不在复述。这种垃圾回收的目的就是尽快的为新生成的对象腾出空间,将生命周期较长的对象放入年老代。

    Full GC 对整个堆进行整理,当年老代或者持久代被写满时或者java程序中system.gc()被调用时会触发。Full gc的执行会引起程序的短时间暂停,因此如何合理有效的分配堆空间,减少Full gc的次数是JVM优化的一个重要内容。

来自深入jvm体系结构书的解释:

什么情况下触发垃圾回收

   由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge(minor) GCFull GC

Scavenge GC

   一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发ScavengeGC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。

 

Full GC

   对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个对进行回收,所以比ScavengeGC要慢,因此应该尽可能减少FullGC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC:

·年老代(Tenured)被写满

·持久代(Perm)被写满 

·System.gc()被显示调用 

·上一次GC之后Heap的各域分配策略动态变化


0 0
原创粉丝点击