GC的两种判定方法


1、引用计数法

如果某个地方引用了这个对象就+1,如果失效了就-1,当为0就会回收但是JVM没有用这种方式,因为无法判定相互循环引用(A引用B,B引用A)的情况

 

所谓引用计数法就是给每一个对象设置一个引用计数器,每当有一个地方引用这个对象时,就将计数器加一,引用失效时,计数器就减一。当一个对象的引用计数器为零时,说明此对象没有被引用,也就是“死对象”,将会被垃圾回收。
引用计数法有一个缺陷就是无法解决循环引用问题,也就是说当对象A引用对象B,对象B又引用者对象A,那么此时A,B对象的引用计数器都不为零,也就造成无法完成垃圾回收,所以主流的虚拟机都没有采用这种算法。

 

2、引用链法(可达性分析)

通过一种GC ROOT的对象(虚拟机栈(栈帧中的本地变量表)中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI(即一般说的Native方法)引用的对象)来判断,如果有一条链能够到达GC ROOT就说明,对象还在被引用,不能到达GC ROOT就说明对象已经不再被引用,可以回收

可达:

 

 不可达:

  • 虽然这些算法可以判定一个对象是否能被回收,但是当满足上述条件时,一个对象不一定会被回收。当一个对象不可达GCRoot时,这个对象并不会立马被回收,而是处于一个死缓的阶段,若要被真正的回收需要经历两次标记如果对象在可达性分析中没有与GCRoot的引用链,那么此时就会被第一次标记并且进行一次筛选,筛选的条件是是否有必要执行finalize()方法。当对象没有覆盖finalize0方法或者已被虚拟机调用过,那么就认为是没必要的。如果该对象有必要执行finalize0方法,那么这个对象将会放在一个称为F-Queue的对队列中,虚拟机会触发一个Finalize0线程去执行,此线程是低优先级的,并且虚拟机不会承诺一直等待它运行完,这是因为如果finalize()执行缓慢或者发生了死锁,那么就会造成F-Queue队列一直等待,造成了内存回收系统的崩溃。执行方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。
  • finalize0方法是Object提供的的实例方法,子类可以覆盖这个方法来做一些系统资源的释放或者数据的清理可以在finalize()让这个对象再次被引用,避免被GC回收;但是最常用的目的还是做cleanup,Java不保证这个finalize()一定被执行。有⼀种JNI(Java Native Interface)调⽤用non-​Java程序(C或C++), finalize()的⼯工作就是回收这部分的内存。
  • 创建对象的时候调用构造函数,销毁对象的时候调用析构(如:finalize)函数,即一个对象变为垃圾的时候会自动调用finalize函数

 在Student类里面重写finalize方法:

    public String sname;
    public int age;
    protected  void finalize(){
        System.out.println("finalize方法执行了");
    }

测试:

 public static void main(String[] args) {
        Student student=new Student("zhai",12);
        student=new Student("zhang",13);
        System.gc();//强制回收垃圾,不调用gc函数,finalize方法不一定执行
    }

 

3、java的垃圾回收机制

在java中,程序员是不需要显式地去释放一个对象的内存的,而是由虚拟机自行执行。在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫描那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM