JVM 怎么判断对象已经死了?

做者:勿念先生
https://blog.csdn.net/moHedon...

GC的历史比Java还有久远,咱们在思考GC时候须要思考三个问题:java

哪些内存须要回收?面试

何时回收?算法

如何回收?后端

在Java中程序计数器、虚拟机栈、本地方法栈这三个区域随线程而生,随线程而灭:栈中的栈帧随着方法的调用和退出而有条不紊的进行着入栈和出栈的过程。微信

每一个栈帧分配多少内存在类结构肯定下来时就已知的,方法结束或者线程结束内存天然跟着回收了。多线程

而Java堆和方法区不同,一个接口中的多个实现类的内存可能不同,每一个方法的多个分支须要的内存也可能不同,咱们只有在程序运行时候才知道会建立哪些对象,这部份内存的分配和回收都是动态的。架构

1、判断对象已死的算法工具

1)引用计数算法.net

给对象添加一个引用计数器,每当一个地方引用它时候,计数器就加1,当引用失效,计数器就减1;任什么时候刻计数器为0的对象就是不可能再被使用了。线程

这种方法实现简单,效率高,可是它很难解决对象的循环引用问题:

public class Test {

    private static final int _1MB = 1024 *1024;

    private Object instance = null;

    public static void testGC(){
        Test objectA = new Test();
        Test objectB = new Test();

        objectA.instance = objectB;
        objectB.instance = objectA;

        objectA = null;
        objectB = null;

        // 假如这里发生GC,objectA和objectB会不会被回收

    }
}

2)可达性分析算法

这个算法的基本思路是经过一系列称为“GC Roots”(一组必须活跃的引用)做为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链时候,那么证实此对象是不可用的。

Java语言中,作做为GC Roots的对象包括如下几种:

1)虚拟机栈(栈帧中的本地变量表)中引用的对象。

2)方法区中类静态属性引用的对象。

3)方法区中常量引用的对象。

4)本地方法栈JNI(即通常说的Native方法)引用的对象。

2、引用

不管是经过引用计数器算法判断对象的引用数量,仍是经过可达性分析算法判断对象引用链是否可达,判断对象是否可活都离不开引用,Java中将引用分为四种:

1)强引用(Strong Reference)

是指程序代码中广泛存在的,相似“Object obj = new Object()”这类的引用,只有强引用还存在对象就不会被回收。

2)软引用(Soft Reference)

软引用是用来描述一些还有用可是非必须的对象。对于软引用关联的对象,在系统将于发生内存溢出异常以前,将会把这些对象列进回收范围中进行二次回收。

3)弱引用(Weak Reference)

也是用来描述非必须对象的,强度比软引用还弱一些,被软引用关联的对象只能存活到下一次内存回收以前。

4)虚引用(Phantom Referenece)

也成为幽灵引用和幻影引用,为一个对象设置虚引用关联的惟一目的就是能在这个对象被回收时收到一个系统通知。

3、生存仍是死亡

即便在可达性分析算法中不可达的对象,也并不是必定是“非死不可”的,这时候他们暂时处于“缓刑”阶段,真正宣告一个对象死亡至少要经历两个阶段:

1)若是对象在可达性分析算法中不可达,那么它会被第一次标记并进行一次刷选,刷选的条件是是否须要执行finalize()方法(当对象没有覆盖finalize()或者finalize()方法已经执行过了(对象的此方法只会执行一次)),虚拟机将这两种状况都会视为没有必要执行)。

2)若是这个对象有必要执行finalize()方法会将其放入F-Queue队列中,稍后GC将对F-Queue队列进行第二次标记,若是在重写finalize()方法中将对象本身赋值给某个类变量或者对象的成员变量,那么第二次标记时候就会将它移出“即将回收”的集合。

finalize()能作的工做,使用try-finally或者其余方式都能作到更好,更及时,因此不建议使用此方法。

4、方法区回收

永久代中回收的内容主要是两部分:废弃的常量和无用的类。判断无用的类(类卸载)必须知足三个条件:

1)该类因此的实例都已经被回收

2)加载该类的ClassLoader被回收

3)该类对应的java.lang.Class对象没有在任何地方引用,没法在任何地方经过反射访问该类的方法

你们能够关注下栈长的微信公众号:Java技术栈,回复:福利,能够免费获取一份我整理的 2020 最新 Java 面试题,真的很是全(含答案),无任何套路。

推荐去个人博客阅读更多:

1.Java JVM、集合、多线程、新特性系列教程

2.Spring MVC、Spring Boot、Spring Cloud 系列教程

3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程

4.Java、后端、架构、阿里巴巴等大厂最新面试题

以为不错,别忘了点赞+转发哦!