JVM GC理论基础

        JVM中的程序计数器、虚拟机栈、本地方法栈与线程的生命周期同生同死。当线程执行完成的时候,他们所占用的内存就自然跟着一起释放了。所以只需要关注堆和方法区的gc问题,尤其是堆,因为一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,这部分内存的分配和垃圾回收都是动态的

一、gc判断算法

    1、引用计数法(Refrence Counting)

        每个对象对应一个计数器,当有一个地方引用时,计算器加1,当引用失效时则进行-1。则当计算器为0时则表示可以进行回收。其优点就是计算效率高,缺点是当A和B出现相互引用(出现引用环)时,本应该被回收,但是计数器不为0,不能进行回收。

    2、可达性分析算法(Reachability Analysis

        可达性分析算法即从GC roots对象开始作为起点,从这些节点开始向下搜索,搜索时所有走过的路径称为引用链()节点,若对象与gc roots不可达则说明可以被回收。 并不是所有不可达的对象都可以被回收,如java中调用finalize()。可达性分析算法解决了相互引用的问题,如下图:

    那么说明可以作为Root节点呢,如下:
    1)、虚拟机栈中本地变量表引用的对象
    2)、方法区

        - 类静态变量引用的对象

        - 常量引用的对象

    3)、本地方法栈中JNI(就是native方法)引用的对象

    3、再谈引用

    JDK1.2以后将对象分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)四种,并且引用的强弱依次减弱。内存中很多对象除了是否被引用而回收,还有很多对象则需要根据实际情况进行判断,比如当内存还比较充裕的情况下则可以不进行gc,当内存比较吃紧的情况下则需要进行gc。所以有以下情况:

    1)、强引用(如 Object obj = new Object())的情况下,只要引用还存在则不能被gc

    2)、软引用(可继承SoftReference类实现软引用)用于描述可用但非必须的对象,当系统将要发生内存溢出前,会将对象列为第二次回收的范围。

    3)、弱引用(可继承WeakReference类实现弱引用)则会在能被回收的下一次gc中进行回收

    4)、虚引用(可继承PhantomReference类实现虚引用)不会对gc回收产生任何影响,只是当该对象被回收时能收到一个通知

    4、方法区的回收

    方法区中主要可以被回收的是不使用的常量和不使用的类,并且并不是所有的JVM都有方法区的垃圾回收器。其中不使用的常量比较好判断,但是不使用类则需要同时满足:

        1>、该类的所有实例都已经被回收,Java堆中不存在任何该类的实例。

        2>、加载该类的classLoader已经被回收

        3>、该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射机制访问该类。

    在大量使用反射、动态代理和CGlib的ByteCode框架中,以及动态生成jsp以及OSGi的频繁自定义classLoader的场景,都需要虚拟机具备卸载功能,保证永久代不会溢出。

二、回收算法

    1、标记-清除算法(Mark-Sweep)

        标记清除算法,会产生空间碎片。


    2、复制回收算法(Copying)

        复制回收算法不会参数空间碎片,但是需要双倍的空间。


    3、标记-整理算法(Mark-Compact)

    4、分代收集算法(Generational Collection)

    比如讲内存分为新生代和老年代,由于新生代中大对数对象都是朝生夕死,所有可以使用复制回收算法对少量的对象进行复制即可,而老年代中大对数对象对象成活率高,并且没有额外的空间进行分配担保,所以只能使用标记清除或标记整理算法。

   

猜你喜欢

转载自blog.csdn.net/it_lihongmin/article/details/80596453