什么样的对象是垃圾?
JDK1.2:没有被引用的对象既是垃圾
JDK1.2之后:无法到达GC ROOTS顶点的对象即为垃圾
怎样判断对象是否被引用?
-
JDK1.2时期:引用计数算法
- 对每个对象创建一个计数器,如果有一个引用指向它,其计数器+1,当一个引用不再指向他时,其计数器-1,最后判断这个计数器是否大于0,如果大于0,说明有引用指向它,如果不大于0,表示没有引用指向它,其即为垃圾。
- 在循环引用中会失效
- 根据引用计数算法:当a=null和b=null时,彼此之间还存在相互引用,它们的计数器大于0,所以并不是垃圾;但是引用一旦为null,对象无法被调用,本质上来说它们就是垃圾。所以引用算法存在缺陷!
- 在循环引用中会失效
- 对每个对象创建一个计数器,如果有一个引用指向它,其计数器+1,当一个引用不再指向他时,其计数器-1,最后判断这个计数器是否大于0,如果大于0,说明有引用指向它,如果不大于0,表示没有引用指向它,其即为垃圾。
-
可达性算法:
- 选取一个节点作为GC ROOTS,其他的引用和对象都去指向这个GC ROOTS,如果这些对象能够达到GC ROOTS顶点,那么说明这个对象不是垃圾;反之即为一个垃圾;指向GCROOTs的链叫做GC链
- 选取一个节点作为GC ROOTS,其他的引用和对象都去指向这个GC ROOTS,如果这些对象能够达到GC ROOTS顶点,那么说明这个对象不是垃圾;反之即为一个垃圾;指向GCROOTs的链叫做GC链
-
根据可达性算法:当GC链1或者GC链2断裂时,两个对象都不是垃圾;但是当链1和2都断裂时两对象都无法到达GC ROOTS顶点,两个对象都是垃圾
可作为节点的对象
- 虚拟机栈(栈帧中本地变量表所指向的对象)
- 方法区中类静态属性引用的对象
- 方法区的常量
- native方法中引用的对象
对象的自我拯救
finalize
- 对象的三种状态:
- 可达(非垃圾)
- 可恢复(对象由可达变为不可达的中间状态)
- 当该对象满足以下两个条件时它可能调用finalize方法达到自我拯救的目的:
- finalize方法被重写
- finalize方法未被执行(一个对象的finalize方法能且只能被执行一次)
- 当该对象满足以下两个条件时它可能调用finalize方法达到自我拯救的目的:
- 不可达 (垃圾)
finalize底层有一个低优先的finalizer线程,将这些需要执行的finalize方法放置在一个队列中,如果发现执行代价过高,则直接舍弃,不予执行
finally、final
- finally:
- finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定会被执行(不管有没有抛出异常),经常被用在需要释放资源的情况下
- final:
- final可以用来修饰类,方法和变量
- 修饰类:当用final修饰类的时,表明该类不能被其他类所继承。当我们需要让一个类永远不被继承,此时就可以用final修饰
- final类中所有的成员方法都会隐式的定义为final方法。
- 修饰方法:
- 把方法锁定,以防止继承类对其进行更改。
- final方法意味着“最后的、最终的”含义,即此方法不能被重写
- 若父类中final方法的访问权限为private,将导致子类中不能直接继承该方法,因此,此时可以在子类中定义相同方法名的函数,此时不会与重写final的矛盾,而是在子类中重新地定义了新方法。
- 把方法锁定,以防止继承类对其进行更改。
- 修饰变量:final成员变量表示常量,只能被赋值一次,赋值后其值不再改变。
- 当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。
- final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值
- 修饰类:当用final修饰类的时,表明该类不能被其他类所继承。当我们需要让一个类永远不被继承,此时就可以用final修饰
- final可以用来修饰类,方法和变量