在回答上面问题之前,我们一定要了解JVM在进行垃圾回收时的机制,首先:

一、可达性算法
  要知道对象什么时候死亡,我们需要先知道JVM的GC是如何判断对象是可以回收的。JAVA是通过可达性算法来来判断对象是否存活的。这个算法的基本思路就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots 没有任何引用链相连时,则证明此对象是不可用的。

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

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

* 方法区中类静态属性引用的对象

* 方法区中常量引用的对象

* 本地方法栈中JNI(即一般说的Native方法)引用的对象

引用计数算法:这也是一个判断对象是否存活的算法,相对于可达性算法较为简单,判断效率也很高,但是没有在JAVA中使用。给对象中添加一个引用计数器,每当一个地方引用它时,计数器值就加1;当引用失效时,计数器就减1;任何时刻计数器为0的对象就是不可能再被使用的。

二、引用
  JDK1.2之后,JAVA将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)。

* 强引用:类似Object obj = new Object()这类引用,只要引用还在,垃圾收集器就不会回收掉被引用的对象。

* 软引用:系统发生内存溢出异常之前,会把软引用的对象列进回收范围之中进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。

* 弱引用:只要进行垃圾回收,就会回收掉引用关联的对象。

* 虚引用:不会对生存时间构成影响,唯一的目的是对象被回收时收到一个系统通知。

三、对象的复活及finalize()方法
  即使在可达性算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑阶段”。要真正宣告一个对象的死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots 相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。

如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样做的原因是如果一个对象在finalize()方法中执行缓慢,或者发生了死循环(更极端的情况),将很可能会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。

finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那么在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那么基本上它就真的被回收了。

总结:finalize()并不是必须要执行的,它只能执行一次或者0次。如果在finalize中建立对象关联,则当前对象可以复活一次。Finalizer线程不保证一定执行finalize方法,因为此线程的优先级很低,获得CPU资源有限;而且这样会避免finalize执行缓慢或者发生死循环,从而导致整个GC奔溃

JAVA中GC时finalize()方法是不是一定会被执行?的更多相关文章

  1. 为什么在Java中不使用finalize()方法

    我们都知道finalize()方法是回收分配给对象的内存之前调用垃圾收集器线程的基本语句.在这篇文章中,我们将会深入这个方法. 这篇文章中的章节: 1.finalize()方法不能保证执行(这个将要用 ...

  2. finalize() 方法——Java中垃圾回收提醒方法

    finalize() Java 允许定义这样的方法,它在对象被垃圾收集器析构(回收)之前调用,这个方法叫做 finalize( ),它用来清除回收对象. 例如,你可以使用 finalize() 来确保 ...

  3. 【Java面试题系列】:Java中final finally finalize的区别

    本篇为[Java面试题系列]第三篇,文中如有错误,欢迎指正. 第一篇链接:[Java面试题系列]:Java基础知识常见面试题汇总 第一篇 第二篇链接:[Java面试题系列]:Java基础知识常见面试题 ...

  4. java中substring的使用方法

    java中substring的使用方法 str=str.substring(int beginIndex);截取掉str从首字母起长度为beginIndex的字符串,将剩余字符串赋值给str: str ...

  5. Java中Set的contains()方法

    Java中Set的contains()方法 -- hashCode与equals方法的约定及重写原则 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashCode() a ...

  6. java中BorderLayout的使用方法

    相关设置: 使用BorderLayout布局上下左右中布局5个按键,单击中间的那个按键时就关闭窗口 代码: /**** *java中BorderLayout的使用方法 * 使用BorderLayout ...

  7. java中final,finally,finalize三个关键字的区别

    final 可以作为修饰符修饰变量.方法和类. 被final修饰的变量必须在初始化时给定初值,以后在使用时只能被引用而不能被修改. 被final修饰的方法不能够在子类中被重写(override): 被 ...

  8. Java中Set的contains()方法——hashCode与equals方法的约定及重写原则

    转自:http://blog.csdn.net/renfufei/article/details/14163329 翻译人员: 铁锚 翻译时间: 2013年11月5日 原文链接: Java hashC ...

  9. Java中wait和sleep方法的区别

    1.两者的区别 这两个方法来自不同的类分别是Thread和Object 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法(锁代码块和方法锁). wait ...

随机推荐

  1. Linux CentOS 7的图形界面安装

    1.首先安装X(X Window System) yum groupinstall "X Window System" 2.由于这个软件组比较大,安装过程会比较慢,安装完成后会出现 ...

  2. 重头开始学Qt——day1

    以前学过Qt,但只是为了学分,现在重学. 1. 认识Qt应用程序框架 直接新建一个项目后,自动生成了一下文件,下面一个个理解. (1)main.cpp main.cpp中特别的是QApplicatio ...

  3. POJ 1286 Pólya定理

    Necklace of Beads Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 9162   Accepted: 3786 ...

  4. SyntaxError: Non-ASCII character '\xe4' in file test.py on line 3, but no encoding declared。

    可以查看到pycharm右下角文件的编码方式, 如果编码方式不一致,则在设置中修改编码方式: http://jingyan.baidu.com/article/c843ea0ba55f0977931e ...

  5. PHP.27-TP框架商城应用实例-后台4-使用Gii生成品牌表的代码

    Gii安装[GII适用于商城项目] 将Gii文件夹复到application 是,访问http://xx.com/index.php/gii Gii规则[Gii使用规则与建表规则密切相关] 1.建表字 ...

  6. WPF系列教程——(三)使用Win10 Edge浏览器内核 - 简书

    原文:WPF系列教程--(三)使用Win10 Edge浏览器内核 - 简书 在需要显示一些 H5网站的时候自带的WebBrowser总是显示不了,WebBrowser使用的是IE内核,许多H5新特性都 ...

  7. 使用wsimport命令生成webService客户端代码实例

    wsimport简介 在JDK的bin文件夹中,有一个wsimport.exe工具,可依据wsdl文件生成相应的类文件,将生存在本地这些类文件拷贝到需要使用的项目中,就可以像调用本地的类一样调用web ...

  8. 树莓派Raspberry Pi 3安装步骤

    一.需要的硬件 1.Raspberry Pi 3(Model B+)树莓派.购买>https://item.jd.com/29225467867.html 2.输出5V/2A的电源 3.SD卡( ...

  9. 通过slf4j/log4j的MDC/NDC 实现日志追踪

    在分布式系统或者较为复杂的系统中,我们希望可以看到一个客户请求的处理过程所涉及到的所有子系统\模块的处理日志. 由于slf4j/log4j基本是日志记录的标准组件,所以slf4j/log4j成为了我的 ...

  10. windows 下开发的 .netCore MVC 部署到 Linux(Mint)

    这两天在公司跟同事偶然聊到 .netCore,说到一些趋势什么的.但是说来说去自己也没试过在Linux 机子上部署过,所以就试一下. 尝试之前也在网上看了一些文章,包括 Linux 上.netCore ...