JVM·垃圾收集器与内存分配策略之对象是否可被回收!

时间:2023-03-08 16:32:08
JVM·垃圾收集器与内存分配策略之对象是否可被回收!
1、判断对象已经死去/不再被引用。
    1.1、引用计数算法:给对象添加引用计数器,有个地方引用就+1,引用失效就-1。任何时刻,引用为0,即判断对象死亡。
        1.1.1、优点:实现简单,效率高。
        1.1.2、缺点:在主流的Java虚拟机中不被使用,因为很难解决对象之间相互循环引用的问题。
    1.2、可达性分析算法(Java,C#,lisp):从一系列称为“GC Roots”的对象作为起始点,从这些节点往下搜索,搜索走过的路径称为引用链,当没有引用链可达到某对象时,认为该对象不可到达,即此对象没有被有效引用。
        1.2.1:可做为GC Roots的对象:
                    虚拟机栈中引用的对象
                    方法区中类静态属性引用的对象
                    方法区中常量引用的对象
                    本地方法栈中JNI(Native方法)应用的对象
2、如何判断是否要被回收
    在Java中,采用可达性分析算法。即使判断未不可达的对象,也不会立即宣告对象死亡。在此之前要经过至少两次标记:
    2.1、第一次标记和筛选:当第一次判断该对象不可达(没有与GC Roots相连的引用链)时,进行筛选:是否要执行finalize()方法。
    2.2、第二次:需要finalize()方法的对象会在一个低优先级的F-Queue中排队执行finalize()。如果在finalize()方法中拯救自己,那么就不会死。否则,被回收。
            在finalize()方法中拯救自己:在改方法中重新连接上GC Roots(重新拥有连接GC Roots的引用)
    2.3、总结:对象可以在被GC时自我拯救。这种拯救只有一次机会,因为GC只会调用一次对象的finalize()方法。
            附自我拯救代码:
**
* Created by KEY on 2017/12/4.
*/
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVA_HOOK = null; public void isAlive(){
System.out.println("yes, I am still alive");
}
@Override
protected void finalize() throws Throwable{
super.finalize();
System.out.println("finalize method executed");
FinalizeEscapeGC.SAVA_HOOK = this;
} public static void main(String[] args) throws Throwable{
SAVA_HOOK = new FinalizeEscapeGC(); //对象第一次拯救自己
SAVA_HOOK = null;
System.gc();
//因为finalize优先级很低,所以等他0.5s
Thread.sleep(500);
if(SAVA_HOOK != null){
SAVA_HOOK.isAlive();
}else{
System.out.println("no,I am dead :(");
} //重复以上代码,看是否能第二次拯救自己
//对象第一次拯救自己
SAVA_HOOK = null;
System.gc();
//因为finalize优先级很低,所以等他0.5s
Thread.sleep(500);
if(SAVA_HOOK != null){
SAVA_HOOK.isAlive();
}else{
System.out.println("no,I am dead :(");
}
}
}

  

3、方法区的垃圾回收
    说明:虚拟机规范对于方法区的实现并没有要求是否回收,也没有要求如何回收,甚至没有要求具体的内存定义, 只需要满足方法区规范即可。所以方法区的回收再不同的虚拟机有不同的实现
    方法区的回收主要针对“废弃常量”和“无用的类”。如何判断是否是“无用的类”
    a.该类所有的实例都已经被回
    b.加载该类的ClassLoader被回收
    c.该类对应的java.lang.class对象没有在任何地方被引用,无法再任何地方通过反射访问该类的方法。