JVM|JVM垃圾回收的分代收集思想

在深入理解垃圾回收思想的时候,也要了解一下分代收集理论。
分代收集理论 这个理论主要是建立在两个分代假说之上的:

  1. 弱分代假说(Weak Generational Hypothesis):绝大多数对象都是朝生夕灭的。
  2. 强分代假说(Stong Generational Hypothesis):熬过越多次垃圾收集过程的对象就越难以死亡。
这两个部分共同奠定了后面很多的垃圾收集器的基本设计原则:收集器应该将Java堆划分出不同的区域,然后将回收对象依据年龄分配到不同的区域进行存储,针对不同的区域,又进行不同的垃圾收集。
但在最后也还出现了一个问题,在进行一次只限于新生代区域的收集(Minor GC),但新生代中的对象完全有可能被老年代所引用的,为了找出该区域中的存活对象,就不得不在固定的GC Roots之外,再额外遍历整个老年代所有对象来确保可达性结果的正确性,反过来也是一样的。这种在理论上是可行的,但实际上会对内存回收带来很大的性能负担。
所以就有了第三条经验法则:
  1. 跨代引用假说(Intergenerational Reference Hypothesis):跨代引用相对于同代引用来说仅占极少数。
存在互相引用关系的两个对象,是一个倾向于同时生存或者同时消亡的。
依据这条假说,我们就不再为了少量的跨代引用去扫描整个老年代,也不必浪费空间专门记录每一个对象是否存在哪些跨代引用,只需要在新生代上建立一个全局的数据结构(记忆集),这个结构把老年代划分为若干个小块,标识出老年代的那一块内存会存在跨代引用。
当在这之后再发生Minor GC时,只有包含了跨代引用的小块内存里的对象才会被加入GC Roots中进行扫描。
为什么使用分代收集 那在java虚拟机中为什么要对垃圾的回收使用分代的收集的方法。
在垃圾回收的算法中,并没有一种算法就可以完全替代其他的算法,它们都具有自己独特的优势和特点。分代收集的思想就应运而生。
分代收集,是基于这样的事实:
不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。一般把Java堆分为新生代和老年代,这样就可以根据各个年代的特点来使用不同的回收算法,以提高垃圾回收的效率。
在Java程序运行的过程中,会产生大量的对象,其中有些对象是与业务信息相关的。
比如Http请求中的Session对象、线程、Socket连接,这类对象根业务直接挂钩,因此生命周期都是比较长的。
但是还有一些对象,主要是程序运行过程中生成的临时变量,这些对象生命周期会比较短。比如:String对象,由于其不变类的特性,系统会产生大量的这些对象,有些对象甚至只用一次即可回收。
在目前几乎所有的GC都采用分代收集算法执行垃圾回收的
在主流的HotSpot中,基于分代的概念,GC所使用的内存回收算法必须结合年轻代和老年代各自的特点。
针对不同的区域进行分区收集,进而来提高收集效率。
年轻代(Young Gen)
特点:区域相对老年代来说比较小,对象的生命周期较短、存活率低,回收频繁。
这种情况复制算法的回收整理、速度是最快的。复制算法的效率只和当前存活对象大小相关,因此很适合用于年轻代的回收。而复制算法内存利用率不高的问题,通过hotspot中的两个survivor的设计得到缓解。
老年代(Tenured Gen)
特点:区域较大,对象的声明周期长,存活率高,回收没有年轻代的频率高。
这种情况存在着大量的存活率高的对象,而复制算法明显是很不合理的。一般都是采用标记 - 清除或者 标记- 整理的混合实现。
  1. Mark阶段的开销与存活对象的数量成正比。
  2. Sweep阶段的开销与所管理区域的大小成正相关。
  3. Compact阶段的开销与存活对象的数据成正比。
而分代的思想被现有的虚拟机广泛使用。几乎所有的垃圾回收器都区分新生代和老年代。
【JVM|JVM垃圾回收的分代收集思想】上一篇: >>>> 垃圾回收算法

    推荐阅读