Java垃圾回收机制及算法(1)

笔者上一篇文章简单分享了JVM的内存结构的一些知识点,那么这篇文章就要写一写关于Java领先其他语言的优势点——垃圾回收机制(GC)的相关问题。

堆空间分代划分概念

在Java中,栈的生命周期主要是随着线程的周期来的无需GC操心,GC主要的工作区是在堆中。
那么首先就来讲一讲堆的内部结构,堆空间的分代划分的概念。
Java垃圾回收机制及算法(1)
因为Java是面向对象开发,所以我们Java国际艺术代码管理大师在进行开发任务时会new出许许多多的对象,而大部分的对象都是朝生夕死的,相对来讲只有少部分的对象在进行GC回收后会存活下来,所以我们的对空间便有了分代划分的概念。
堆被划分为新生代、老年代(Tenured),而新生代又划分为Eden和Survivor区,Survivor又分为From Survivor和To Survivor区。
新创建出来的对象都会被放在Eden区,在经过第一次垃圾回收后存活下来的对象会复制到From区或者To区,而Eden区整体数据会被全部清除(格式化),From和To区的作用在我看来是一样的,大小也一样就是为了在就是留存新生代存活下来的又不满足进入老年代对象的地方。在经历了多次回收之后依旧活下来的对象会动态判断对象头中的GC分代年龄,满足才会放到老年代(不同的垃圾回收器判断条件也不同,默认的并发垃圾回收器是15)。

判断对象的存活

堆中存活着几乎所有的对象实例,而在垃圾回收执行前要先判断那些是存活的对象哪些不会再被任何途径使用的对象,而判断是否存活的算法有两种。

  1. 引用计数法(在Java中已经被淘汰)
    这种算法会判断对象被引用的次数,只要被引用一次就会被计数+1,而只要这个对象计数不为0就会认为是被引用中。当出现两个对象都对本质的功能没有作用,但却互相引用就会出现问题,需要进行一系列其他的处理才能判断是无需存活的,会影响效率,所以在Java中这种算法已经被淘汰了。
  2. 可达性分析
    可达性分析也成根可达,这种算法会根据GC Roots的对象作为起始点,根据这些节点向下搜索,从而形成引用链,一个对象没有与GC Roots形成任何引用链的会判断为无需存活。
    GC Roots:(前四种比较重要)
    (1)虚拟机栈(栈帧中的本地变量表)引用的对象;各线程调用方法堆栈使用的参数、局部变量、临时变量等。
    (2)方法区中类静态属性引用的对象;静态变量。
    (3)方法区中常量引用的对象。
    (4)本地方法栈中JNI引用的对象(Native方法)。
    (5)JVM的内部引用(class对象、异常对象)。
    (6)被同步锁持有的对象(synchronized)。
    (7)JVM内部的JMXBean、JVMTITI中注册的回调、本地代码缓存等。
    (8)JVM实现的临时性对象,跨代引用的对象。
    Java垃圾回收机制及算法(1)

垃圾回收算法

复制算法

将可用的内存按容量划分为大小相同的两块区域,每次使用其中的一块区域,当其中的一块区域内存用完后,进行垃圾回收将还存活的对象复制到另一块区域中,并将已经用完的那块区域一次性清楚掉。这里的内存移动是真实的移动,堆中的地址会发生改变,所以需要调整对应的引用地址。
这种算法简单高效,但是缺点是将可用的内存缩小为原来的一半。这种算法适用于新生代的垃圾回收,因为绝对部分对象是朝生夕死的复制过去的对象相对比较少,效率会高一些,而另一半的内存区域清除也是效率非常高的。

  • Appel式回收
    这是一种更加优化的复制回收分代策略,具体的做法是将新生代的Eden区分配的更大,将两块Survivor区From、To分配的更小一些,因为绝大部分对象是朝生夕死的所以无需按照1:1的比例去分配,对象更多的是在Eden区,只有很少的部分会存活下来到达From或To区。HotSpot虚拟机默认Eden和Survivor大小比例是8:1。
    Java垃圾回收机制及算法(1)

标记-清除算法

这个算法分为标记和清除两个阶段。首先会扫描一遍所有对象标记处需要清除的对象,在标记完成后扫描回收所有被标记的对象,所以会扫描两遍。
此算法相对于复制算法效率略低,因为如果大部分对象都是朝生夕死的话会需要大量的标记和回收对象的操作。
它的主要问题是标记清除后会产生大量的不连续的内存碎片,碎片太多的话会导致在需要分配大对象时候找不到足够的连续内存会使垃圾回收提前触发。
这种算法应用于老年代的垃圾回收,因为新生代的回收对象太多,会导致效率变得特别慢,而老年的相对于新生代回收对象不是那么多。
Java垃圾回收机制及算法(1)

标记-整理算法

此算法首先标记出需要回收的对象,标记完成后不会直接进行清除,而是让所有存活的对象向一端移动,移动后直接清除边界以外的数据。此算法没有内存碎片但效率偏低,而且对象的移动需要全称暂停用户线程才能进行,同时由于对象的地址发生变化所有的引用需要进行调整。
此算法也仅用于老年代。
Java垃圾回收机制及算法(1)

关于Java的垃圾回收机制及其算法其实是很有意思的一块知识点,知识点也有点多,今天先分享到这,下一篇文章会介绍具体的不同垃圾回收器的运行过程等知识点。

过了个十一假期感觉心都飞了,接下来会增加更博客的频率,希望一起进步!