共计 1246 个字符,预计需要花费 4 分钟才能阅读完成。
1. 援用计数法
2. 可达性剖析算法
3. 谈一谈 GCRoot
在堆外面寄存着 JAVA 世界中简直所有的对象实例,垃圾收集器在对堆对象进行回收以前,第一件事件就是要确定这些对象之中哪些还“存活”着,哪些曾经“死去”。
1. 援用计数法
援用计数法就是一种断定该对象是否为垃圾对象的办法,它是这么做的:在每个对象中增加一个援用计数器,当有中央援用这个对象的时候,援用计数器就 +1,当援用生效的时候,计数器的值就 -1。任何时刻计数器为 0 的对象就是不可能再被应用的。
这种办法是一个不错的算法,而且非常容易实现,然而 JAVA 虚拟机却 没有选用 援用计数法来治理内存,其中最次要的起因是因为 它很难解决对象之间互相循环援用的问题。
举个简略的例子
ReferenceCountingDemo obj1 = new ReferenceCountingDemo();
ReferenceCountingDemo obj2 = new ReferenceCountingDemo();
obj1.instance = obj2;
obj2.instance = obj1;
obj1 = null;
obj2 = null;
此时咱们能够看出,obj1 和 obj2 曾经没有援用对象了,然而他们的实例属性 instance 还援用这对象,这种状况下,它们各自的计数器的值还是 1,因而,这种办法很难解决对象之前循环援用的问题。
2. 可达性剖析算法
目前的 JAVA 虚拟机是 应用可达性剖析算法 来断定对象是否存活的,这个算法的基本思路就是通过一系列被称为(GCRoot)的对象作为起始点(什么是 GCRoot 咱们下文再谈),从这些节点开始向下搜寻,搜寻所走过的门路成为援用链,,当一个对象没有任何援用链相连,则证实此对象是不可用的,回收。
3. 谈一谈 GCRoot
上文咱们提到过可达性剖析算法通过 GCRoot 开始搜寻,那么有哪些对象能够当做 GCRoot?
a. java 虚拟机栈中的援用的对象。
b. 办法区中的类动态属性援用的对象。(个别指被 static 润饰的对象,加载类的时候就加载到内存中。)
c. 办法区中的常量援用的对象。
d. 本地办法栈中的 JNI(native 办法)援用的对象
接下来咱们就对上述四种状况做一个剖析:
a. java 虚拟机栈中的援用的对象。
咱们都晓得,java 虚拟机在调用办法的时候都会创立一个相应的栈帧,栈帧中蕴含了这个办法外部应用的所有对象的援用,一旦办法执行完结之后,这些长期对象援用也就不复存在了,这些对象就会被垃圾收集器给回收。
b. 办法区中的类动态属性援用的对象。(个别指被 static 润饰的对象,加载类的时候就加载到内存中。)
这个没什么好解释的,就是被 static 润饰的对象,多用于单例模式的写法。
c. 办法区中的常量援用的对象。
也就是被 final 润饰的对象。
d. 本地办法栈中的 JNI(native 办法)援用的对象
最初,真的要宣告对象死亡须要通过两个过程
1. 可达性剖析后没有发现援用链
2. 查看对象是否有 finalize 办法,如果有重写且在办法内实现自救(如再建设援用),还是能够抢救一下。