首先我们需要知道JVM垃圾回收机制自动完成。每种SUN之前,JRockit JVM,收购之后使用Oracle拥有两种JVM实现会合二为一。Oracle SE平台标准核心组件的一部分。市面上探讨垃圾回收机制,默认都是基于Ok,我们切入正题,先来看下JVM的内存区域模型,

 浅析JVM垃圾回收机制_垃圾回收

这张图非常直观的展示了JVM的内存区域划分,我们关注的GC在哪里呢?答案在下面这张图里面。

 

 浅析JVM垃圾回收机制_JVM_02

对比两张图,我们发现,垃圾收集器跟jit编译器一起构成了JVM的执行引擎,gc的“势力范围”是哪里呢?且看下图

 浅析JVM垃圾回收机制_垃圾回收_03

再次强调这是hotspot的堆模型,其他JVM(如JRockit、IBM J9等)是不存在永久代的概念的,有趣的是在Java8中,hotspot也将永久代取消了,改为了metaSpace,直接采用本地内存,这也减轻了堆的压力。

我们暂且看应用更为广泛的JDK8之前的堆分区:

1、新生代(Young Generation):绝大多数最新被创建的对象会被分配到这里,由于大部分对象在创建后会很快变得不可到达,所以很多对象被创建在新生代,然后消失。对象从这个区域消失的过程我们称之为”minor GC“。

Eden空间(Eden space,任何实例都通过Eden空间进入运行时内存区域)

S0 Survivor空间(S0 Survivor space,存在时间长的实例将会从Eden空间移动到S0 Survivor空间)

S1 Survivor空间 (存在时间更长的实例将会从S0 Survivor空间移动到S1 Survivor空间)

2、老年代(Old generation): 对象没有变得不可达,并且从新生代中存活下来,会被拷贝到这里。其所占用的空间要比新生代多。也正由于其相对较大的空间,发生在老年代上的GC要比新生代少得多。对象从老年代中消失的过程,我们称之为”major GC“(或者”full GC“)

S1中的实例,如果存活时间足够长将提升到老年代(Old Generation)。

3、永久代(Permanent Generation)包含类、方法等细节的元信息,也就是JVM内存结构中的方法区,他用来保存类常量以及字符串常量。因此,这个区域不是用来永久的存储那些从老年代存活下来的对象。这个区域也可能发生GC。并且发生在这个区域上的GC事件也会被算为major GC。hotspot由于把GC扩展到方法区,所以把方法区抽象成永久代,作为堆的逻辑结构。再补充一点,著名的字符串常量池在JDK7之前,就在永久代里面,JDK7之后从永久代中挪出到正经的堆中了。毕竟永久代实际上并不在堆里,只是hotspot为了扩张GC的势力范围,才有了上面的那张图。

 

下面我们来看看新生代的GC过程:

新生代是用来保存那些第一次被创建的对象,他可以被分为三个空间

 一个伊甸园空间(Eden )

 两个幸存者空间(Survivor )

一共有三个空间,其中包含两个幸存者空间。每个空间的执行顺序如下:

1、绝大多数刚刚被创建的对象会存放在伊甸园空间。

2、在伊甸园空间执行了第一次GC之后,存活的对象被移动到其中一个幸存者空间。

3、此后,在伊甸园空间执行GC之后,存活的对象会被堆积在同一个幸存者空间。

4、 当一个幸存者空间饱和,还在存活的对象会被移动到另一个幸存者空间。之后会清空已经饱和的那个幸存者空间。

5、在以上的步骤中重复几次依然存活的对象,就会被移动到老年代。

如果你仔细观察这些步骤就会发现,其中一个幸存者空间必须保持是空的。如果两个幸存者空间都有数据,或者两个空间都是空的,那一定标志着你的系统出现了某种错误。