关于gc:03JVM垃圾回收机制

8次阅读

共计 2073 个字符,预计需要花费 6 分钟才能阅读完成。


后面在 jvm 组成构造一文中,说到了 GC 和一些算法,那么在这篇文章里,就具体说说 GC 的罕用算法。
垃圾回收 (Garbage Collection,GC),就是将垃圾回收,防止过于占用内存空间,导致内存透露,对内存堆中曾经死亡或者长时间没有应用的对象进行革除和回收。
既然是垃圾回收,那么如何判断哪些对象是垃圾,须要被回收呢?

如何找到程序里的垃圾

(1)援用计数法


援用计数法其实就是给每个对象增加一个计数器 RC,当有中央援用该对象时计数器加 1,当援用生效时计数器减 1。通过对象计数器是否为 0 来判断对象是否可被回收。然而相应的,它无奈解决循环援用的问题。
倘若如下:
定义一个字符串

String str = new String ("tony");

其实这个时候,str 援用了字符串 ”tony”,那么这个字符串援用次数就是 1,这时候如果 m 指向了另一个新的值,例如 m=null,那这个时候 ”tony” 的援用次数就成了 0 了,也就意味着要被回收了。

public class ReferenceCountingGC {

  public Object instance;

  public ReferenceCountingGC(String name) { }
  public static void testGC(){ReferenceCountingGC a = new ReferenceCountingGC("objA");
    ReferenceCountingGC b = new ReferenceCountingGC("objB");

    // a 和 b 相互援用了
    a.instance = b;
    b.instance = a;

    a = null;
    b = null;
  }
}

从代码中能够看出,a,b 这两个对象始终在相互援用,如果采纳援用计数法的话,是永远无奈 GC 它们的,因为它们的援用计数永远都不会为 0,所以说援用计数法是有局限性的,或者说它不属于严格意义上的垃圾收集机制。

(1)可达性剖析算法


GC ROOT是什么?

  • 首先咱们晓得标记算法,JVM 的标记算法咱们能够理解为一个可达性算法,所以所有的可达性算法都会有终点,那么这个终点就是 GC Root。也就是须要通过 GC Root 找出所有活的对象,那么剩下所有的没有标记的对象就是须要回收的对象。
  1. 通过 GC ROOT的对象作为搜寻起始点,通过援用向下搜寻,所走过的门路称为援用链。通过对象是否有达到援用链的门路来判断对象是否可被回收(可作为 GC ROOT 的对象:虚拟机栈中援用的对象,办法区中类动态属性援用的对象,办法区中常量援用的对象,本地办法栈中 JNI 援用的对象)
  2. 通过可达性算法,胜利解决了援用计数所无奈解决的循环依赖问题,只有你无奈与 GC Root 建设间接或间接的连贯,零碎就会断定你为可回收对象。那这样就引申出了另一个问题,哪些属于GC Root
  3. Java 内存区域中哪些能够作为 GC Root 对象?

虚拟机栈中援用的对象

public class StackLocalParameter {public StackLocalParameter(String name) {}

  public static void testGC() {StackLocalParameter s = new StackLocalParameter("localParameter");
    s = null;
  }
}

办法区中类动态属性援用的对象

public class MethodAreaStaicProperties {

  public static MethodAreaStaicProperties m;

  public MethodAreaStaicProperties(String name) {}

  public static void testGC(){MethodAreaStaicProperties s = new MethodAreaStaicProperties("properties");
    s.m = new MethodAreaStaicProperties("parameter");
    s = null;
  }
}

办法区中常量援用的对象

public class MethodAreaStaicProperties {public static final MethodAreaStaicProperties m = MethodAreaStaicProperties("final");

  public MethodAreaStaicProperties(String name) {}

  public static void testGC() {MethodAreaStaicProperties s = new MethodAreaStaicProperties("staticProperties");
    s = null;
  }
}

本地办法栈中援用的对象

任何 native 接口都会应用某种本地办法栈,实现的本地办法接口是应用 C 连贯模型的话,那么它的本地办法栈就是 C 栈。当线程调用 Java 办法时,虚构机会创立一个新的栈帧并压入 Java 栈。然而当它调用的是本地办法时,虚构机会放弃 Java 栈不变,不再在线程的 Java 栈中压入新的帧,虚拟机只是简略地动静连贯并间接调用指定的本地办法。

正文完
 0