JVM 垃圾回收算法

GC触发时机

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

Scavenge GC

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

Full GC

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

a)  年老代(Tenured)被写满;

b)  持久代(Perm)被写满;

c)  System.gc()被显示调用;

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

 

垃圾回收算法

1.标记-清除算法

        最基础的垃圾回收算法,分为两个阶段,标记和清除;这种算法的缺点是:效率比较低;内存碎片化严重。

JVM 垃圾回收算法_第1张图片

2.复制算法

        复制算法将可用的内存分成两份,每次使用其中一块,当这块回收之后把未回收的复制到另一块内存中,然后把使用的清除。这种算法运行简单,解决了标记-清除算法的碎片问题,但是这种算法代价过高,需要将可用内存缩小一半,对象存活率较高时,需要持续的复制工作,效率比较低。

JVM 垃圾回收算法_第2张图片

3.标记整理算法

        标记整理算法是针对复制算法在对象存活率较高时持续复制导致效率较低的缺点进行改进的,该算法是在标记-清除算法基础上,不直接清理,而是将存活对象移向内存的一端,然后清除一端边界以外的内存,这样既可以避免不连续空间出现,还可以避免对象存活率较高时的持续复制。

JVM 垃圾回收算法_第3张图片

4.分代收集算法

      分代收集算法是目前大部分JVM所采用的的方法,其核心思想是根据对象的存活的不同生命周期将内存划分为不同的域,一般情况下将GC堆划分为老生代和新生代。老生代的特点是每次垃圾回收时只有少量对象需要被回收,新生代的特点是每次垃圾回收时都有大量垃圾需要被回收,因此可以根据不同区域选择不同的算法。

  • 新生代的的复制算法

       所有新生成的对象首先都是放在新生代的,新生代的目标就是尽可能快速的收集掉那些生命周期短的对象 。

      (1). 新生代的内存按照8:1:1的比例分为一个eden区和两个survivor(survivorFrom,survivorTo)区。大部分对象在eden区生成,回收时先将eden区存活对象复制到一个survivorFrom区,然后清空eden区,当这个survivorFrom区也存放满时,则将eden区和survivorFrom区的存活对象一起复制到另一个survivorTo区,然后清空eden区和survivorFrom区,交换survivorFrom与survivorTo区保持survivorTo区为空,如此往复。

      (2).当survivorTo区的内存不足以存放eden区和survivorFrom区的对象时,就将存活对象放入老生代。当老生代也满时则出发一次Full GC,也就是新生代和老生代一起进行垃圾回收。新生代发生的垃圾回收也称Minor GC。

JVM 垃圾回收算法_第4张图片

  • 老年代的标记复制算法

        a). 在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。

        b) .内存比新生代也大很多(大概比例是1:2),当老年代内存满时触发Full GC,Full GC发生频率比较低,老年代对象存活时间比较长,存活率标记高。

 

       

   

 

你可能感兴趣的:(JVM)