简介什么是终极算法?其实就是现在JVM使用的算法,并不是真正的ultimate。也许几年后,会有新的终极算法,而且几乎肯定会有,因为我相信高级人的能力。那么分代收集算法是如何处理GC的呢?对象分类分代收集算法是针对对象的不同特性,采用合适的算法,没有实际的新算法。与其说分代收集算法是第四种算法,不如说它是前三种算法的实际应用。首先我们来讨论一下对象的不同特性,然后我们会和大家一起为这些对象选择GC算法。内存中的对象根据其生命周期的长短大致可以分为三种。以下姓名均为个人姓名。1.早逝的对象:短时间内死亡的对象,通俗地说,就是活不长就会死的对象。例子:某个方法的局部变量,循环中的临时变量等。2.不朽的主体:这种主体一般都活得很长,也不是很老就死了,但归根结底是不朽的臣民迟早会差点死,但也只是差点而已。例子:缓存对象、数据库连接对象、单例对象(singletonpattern)等。3.不朽的对象:这些对象一般一出生就几乎是不朽的,而且几乎永远都活着,记住,只是几乎不朽。例子:String池中的对象(享元模式),加载的类信息等。对象对应的内存区域还记得我们前面介绍内存管理时JVM对内存的划分吗?我们将以上三个对象映射到内存区,即aborted对象和老永生对象都在JAVA堆中,永生对象在方法区。我们在上一章已经说过,对于JAVA堆,JVM规范要求必须实现GC。因此,对于早熟的对象和老不朽的对象来说,死亡几乎是一个必然的结果,但也只是几乎,难免会有一些对象活到应用结束。但是JVM规范并没有要求方法区的GC,所以假设一个JVM实现没有对方法区进行GC,那么坚不可摧的对象才是真正的坚不可摧的对象。因为永生对象的生命周期太长,分代收集算法是针对JAVA堆设计的,即早熟对象和老永生对象。JAVA堆的对象回收(aborted对象和oldimmortal对象)有了上面的分析,我们来看看分代收集算法是如何处理JAVA堆的内存回收的,即aborted对象和oldimmortal对象的回收.Abortedobject:这种对象生生死死,存活时间短。还记得复制算法的使用要求吗?即对象的存活率不能太高,所以中止的对象最适合复制算法。小问题:内存浪费了50%怎么办?答:因为中止对象的存活率普遍较低,所以没有必要使用50%的内存作为空闲。一般使用两块10%的内存作为free和active区间,另外80%的内存用于为新对象分配内存。一旦GC发生,转移10%的活动空间和另外80%到10%的空闲空间中存活的对象,然后释放之前的90%内存,以此类推。为了让大家更清楚的看到GC的过程,LZ给出了下图。图中标出了三个区域在每个阶段各自的内存情况。相信看图,它的GC流程就不难理解了。不过有两点需要LZ说一下。第一点是,使用这种方法,我们只浪费了10%的内存。这是可以接受的,因为我们换来的是内存的整齐排列和GC的速度。第二点,这个策略的前提是每个存活对象占用的内存不能超过这个10%的大小。一旦超出,多余的对象将无法复制。为了解决上述突发情况,即当存活对象占用的内存过大时,专家们将JAVA堆分成两部分来处理。以上三个区域是第一部分,称为新生代或年轻一代。剩下的部分,专门用来存放旧的不死对象,称为老年代。是不是很贴切的名字呢?让我们看看如何处理旧的不死物体。老亡灵对象:这类对象的存活率非常高,因为大部分都是从新生代转移过来的。就像人一样,活久了,就会长生不老。通常,当出现以下两种情况时,对象就会从新生代区转移到老年代区。1.新生代中的每个对象都会有一个年龄。当这些对象的年龄达到一定程度(年龄就是存活过的GC次数,如果对象每次GC都存活下来,年龄会增加1),就会被转移到老年代,并且这个转移到老年代的年龄值一般可以在JVM中设置。2.当新生代中存活的对象占用内存超过10%时,多余的对象会被放到老年代。这时老年代就是新生代的“后备仓库”。对于老不朽对象的特性,显然已经不适合使用复制算法了,因为它的存活率太高了,而且不要忘记如果老年代再次使用复制算法,它是没有备份的仓库。因此,对于旧的亡灵对象,一般只能使用标记/排序或标记/清除算法。方法区的对象回收(不可破坏的对象)以上两种情况已经解决了GC的大部分问题,因为JAVA堆是GC的主要关注点,上面也已经包含了分代收集算法的所有内容。接下来,对于坚不可摧的对象的回收不再是分代收集算法的一部分。方法区中存在不朽对象。在我们常用的hotspot虚拟机(JDK默认的JVM)中,方法区也被亲切地称为永久代,是不是很贴切呢?其实在很久以前,就没有永久代。当时永久代和老年代是放在一起的,里面包含了JAVA类的实例信息和类信息。但是后来发现类信息的卸载很少发生,所以把两者分开。幸运的是,这样做确实可以大大提高性能。所以永久代被分出来了。这部分区域的GC采用与老年代类似的方式。由于没有“备库”,两者都只能使用mark/clear和mark/sort算法。JVM在进行GC的时候,并不会每次都将以上三个内存区域一起回收。大多数时候,回收指的是新一代。所以GC根据回收的区域分为两种,一种是普通GC(minorGC),另一种是globalGC(m??ajorGC或FullGC)。他们针对的领域如下。普通GC(minorGC):只针对新生代区域进行GC。GlobalGC(m??ajorGC或FullGC):针对老年代的GC,偶尔伴随着新生代的GC和永久代的GC。由于老年代和永久代的GC效果都比较差,而且两者内存占用的增长速度也比较慢,所以一般情况下,需要经过几次普通GC才会触发一次全局GC。
