zoukankan      html  css  js  c++  java
  • Java对象——死或生

    本文是《深入理解Java虚拟机》3.2节的读书笔记,理解有误的地方欢迎指正

    如何判断对象是否可以回收,传统的做法是引用计数法:

    引用计数算法:给对象添加一个引用计数器,每当一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻引用计数器值为0的对象就是不可能再被使用的。

    引用计数算法看起来简单明了,但是却存在一个麻烦的问题——即循环引用。假设现在我使用引用计数算法回收对象,有如下代码正在执行:

    public class  Test {
        public Object instance = null;
        public static void main(String[] args){
            Test a = new Test();
            Test b = new Test();
            a.instance = b;
            b.instance = a;
            //...
        }
    }

    当我想回收对象a的时候,发现它被对象b引用,那么要使它的引用计数为0,必须先干掉对象b。但是当我掉头去准备先干掉对象b的时候,却发现它被对象a引用,于是要干掉b必须先干掉a。。。如此,陷入了一种死锁的状态。最后,在整个程序执行期间,对象a和b都得不到回收,造成内存泄漏。

    由于循环引用等问题,主流Java虚拟机中没有选用引用计数算法来管理内存,而是使用 可达性分析算法

    可达性分析算法:通过一系列称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连(用图论的话来说,就是从 GC Roots 到这个对象不可达)时,则证明此对象是不可用的。



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

    • 虚拟机栈(栈帧中的本地变量表)中引用的对象
    • 方法区中的类静态属性(static修饰)引用的对象
    • 方法区中常量(final修饰/字符串常量)引用的对象
    • 本地方法栈中JNI(即Native方法)引用的对象



    当通过可达性分析算法发现对象不可达时,并不能就此宣告对象死亡,宣告一个对象的死亡至少要经过两次标记过程:

    当第一次发现对象通过 GC Roots 不可达时,该对象将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。(当对象实现了finalize()方法并且该方法未被虚拟机调用过,则判定该对象有必要执行finalize()方法)。
     
    无必要执行finalize()方法的对象等待下一次标记的时候宣告死亡。有必要执行finalize()方法的对象被放入F-Queue队列中,该队列将由虚拟机自动建立的、低优先级的Finalizer线程执行。
     
    对象可以在finalize()方法中将自己重新与 GC Roots 引用链建立联系,这样在下一次标记时,就会被移出 “即将回收” 的集合。否则,二次标记后就可以被回收了。

  • 相关阅读:
    温故而知新-错误和异常处理
    温故而知新-面向对象的PHP
    Django框架之模板语法【转载】
    django2.0实现数据详情页展示的流程
    django2.0表的ORM字段类型和展示
    Fatal error: Cannot use object of type PHPExcel_RichText as array
    django2.0数据展示流程
    django2.0模板相关设置
    django2.0新增功能流程
    django2.0设置默认访问路由
  • 原文地址:https://www.cnblogs.com/read-the-spring-and-autumn-annals-in-night/p/12041951.html
Copyright © 2011-2022 走看看