Java GC、新生代、老年代

  • Post author:
  • Post category:java



Java


中的堆是 JVM

所管理的最大的一块内存空间,主要用于存放各种类的实例对象。

在 Java 中,

堆被划分成两个不同的区域:新生代 ( Young )

、老年代 ( Old )。


新生代 ( Young )

又被划分为三个区域:

Eden


、From Survivor

、To Survivor。


这样划分的目的是为了使 JVM

能够更好的管理堆内存中的对象,包括内存的分配以及回收。

堆的内存模型大致为:


从图中可以看出:




堆大小 =

新生代 + 老年代

。其中,堆的大小可以通过参数 –Xms

、-Xmx 来指定。


(本人使用的是 JDK1.6,以下涉及的 JVM 默认值均以该版本为准。)

默认的,新生代 ( Young ) 与老年代 ( Old ) 的比例的值为



1:2




(


该值可以通过参数 –XX:NewRatio

来指定

),即:新生代 ( Young ) = 1/3 的堆空间大小。老年代 ( Old ) = 2/3 的堆空间大小。其中,新生代 ( Young )

被细分为 Eden 和 两个 Survivor 区域,这两个 Survivor 区域分别被命名为 from 和 to,以示区分。


默认的,

Edem : from : to = 8 :1 : 1




(


可以通过参数–XX:SurvivorRatio

来设定 ),即: Eden = 8/10 的

新生代空间大小,from = to = 1/10 的新生代空间大小。



JVM


每次只会使用 Eden

和其中的一块 Survivor 区域来为对象服务,所以无论什么时候,总是有一块Survivor

区域是空闲着的。

因此,新生代实际可用的内存空间为 9/10 ( 即90% )的新生代空间。



GC





Java


中的堆也是 GC

收集垃圾的主要区域。

GC


分为两种:Minor GC

、FullGC ( 或称为 Major GC )。

Minor GC 是


发生在新生代中



的垃圾收集动作,



所采用的是复制算法





新生代几乎是所有 Java

对象出生的地方,即 Java 对象申请的内存以及存放都是在这个地方。Java 中的大部

分对象通常不需长久存活,具有朝生夕灭的性质。

当一个对象被判定为 “死亡” 的时候,GC 就有责任来回收掉这部分对象的内存空间。新生代是 GC 收集垃圾的

频繁区域。

当对象在 Eden ( 包括一个 Survivor 区域,这里假设是 from 区域 ) 出生后,


在经过一次 Minor GC

后,如


果对象还存活,并且能够被另外一块 Survivor 区域所容纳


(


上面已经假设为 from

区域,这里应为 to 区域,

即 to 区域有足够的内存空间来存储 Eden 和 from 区域中存活的对象 ),


则使用复制算法将这些仍然还存活的对



象复制到另外一块 Survivor

区域 ( 即 to 区域 ) 中


,然后清理所使用过的 Eden

以及 Survivor 区域 ( 即

from 区域 ),


并且将这些对象的年龄设置为1

,以后对象在 Survivor 区每熬过一次 Minor GC,就将对象的年


龄 + 1,当对象的年龄达到某个值时 ( 默认是 15 岁,可以通过参数 -XX:MaxTenuringThreshold 来设定


),这些对象就会成为老年代。


但这也不是一定的,



对于一些较大的对象 (

即需要分配一块较大的连续内存空间 ) 则是直接进入到老年代







Full GC






发生在老年代



的垃圾收集动作,所采用的是



标记-

清除算法




现实的生活中,老年代的人通常会比新生代的人”

早死”。堆内存中的老年代(Old)不同于这个,老年代里面的对象

几乎个个都是在 Survivor 区域中熬过来的,它们是不会那么容易就 “死掉” 了的。因此,


Full GC


发生的次数不



会有 Minor GC

那么频繁,并且做一次 Full GC 要比进行一次 Minor GC 的时间更长。





另外,


标记-

清除算法收集垃圾的时候会产生许多的内存碎片



(


即不连续的内存空间 )

,此后需要为较大的对象

分配内存空间时,若无法找到足够的连续的内存空间,就会提前触发一次 GC 的收集动作。