1. finalize的作用

  • finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法。
  • finalize()与C++中的析构函数不是对应的。C++中的析构函数调用的时机是确定的(对象离开作用域或delete掉),但Java中的finalize的调用具有不确定性
  • 不建议用finalize方法完成“非内存资源”的清理工作,但建议用于:① 清理本地对象(通过JNI创建的对象);② 作为确保某些非内存资源(如Socket、文件等)释放的一个补充:在finalize方法中显式调用其他资源释放方法。其原因可见下文[finalize的问题]

2. finalize的问题

  • 一些与finalize相关的方法,由于一些致命的缺陷,已经被废弃了,如System.runFinalizersOnExit()方法、Runtime.runFinalizersOnExit()方法
  • System.gc()与System.runFinalization()方法增加了finalize方法执行的机会,但不可盲目依赖它们
  • Java语言规范并不保证finalize方法会被及时地执行、而且根本不会保证它们会被执行
  • finalize方法可能会带来性能问题。因为JVM通常在单独的低优先级线程中完成finalize的执行
  • 对象再生问题:finalize方法中,可将待回收对象赋值给GC Roots可达的对象引用,从而达到对象再生的目的
  • finalize方法至多由GC执行一次(用户当然可以手动调用对象的finalize方法,但并不影响GC对finalize的行为)

3. finalize的执行过程(生命周期)

(1) 首先,大致描述一下finalize流程:当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。
(2) 具体的finalize流程:
对象可由两种状态,涉及到两类状态空间,一是终结状态空间 F = {unfinalized, finalizable, finalized};二是可达状态空间 R = {reachable, finalizer-reachable, unreachable}。各状态含义如下:
  • unfinalized: 新建对象会先进入此状态,GC并未准备执行其finalize方法,因为该对象是可达的
  • finalizable: 表示GC可对该对象执行finalize方法,GC已检测到该对象不可达。正如前面所述,GC通过F-Queue队列和一专用线程完成finalize的执行
  • finalized: 表示GC已经对该对象执行过finalize方法
  • reachable: 表示GC Roots引用可达
  • finalizer-reachable(f-reachable):表示不是reachable,但可通过某个finalizable对象可达
  • unreachable:对象不可通过上面两种途径可达
状态变迁图:
变迁说明:
  1. 新建对象首先处于[reachable, unfinalized]状态(A)
  2. 随着程序的运行,一些引用关系会消失,导致状态变迁,从reachable状态变迁到f-reachable(B, C, D)或unreachable(E, F)状态
  3. 若JVM检测到处于unfinalized状态的对象变成f-reachable或unreachable,JVM会将其标记为finalizable状态(G,H)。若对象原处于[unreachable, unfinalized]状态,则同时将其标记为f-reachable(H)。
  4. 在某个时刻,JVM取出某个finalizable对象,将其标记为finalized并在某个线程中执行其finalize方法。由于是在活动线程中引用了该对象,该对象将变迁到(reachable, finalized)状态(K或J)。该动作将影响某些其他对象从f-reachable状态重新回到reachable状态(L, M, N)
  5. 处于finalizable状态的对象不能同时是unreahable的,由第4点可知,将对象finalizable对象标记为finalized时会由某个线程执行该对象的finalize方法,致使其变成reachable。这也是图中只有八个状态点的原因
  6. 程序员手动调用finalize方法并不会影响到上述内部标记的变化,因此JVM只会至多调用finalize一次,即使该对象“复活”也是如此。程序员手动调用多少次不影响JVM的行为
  7. 若JVM检测到finalized状态的对象变成unreachable,回收其内存(I)
  8. 若对象并未覆盖finalize方法,JVM会进行优化,直接回收对象(O)
  9. 注:System.runFinalizersOnExit()等方法可以使对象即使处于reachable状态,JVM仍对其执行finalize方法

4. 一些代码示例

(1) 对象复活

  1. public class GC {
  2. public static GC SAVE_HOOK = null;
  3. public static void main(String[] args) throws InterruptedException {
  4. SAVE_HOOK = new GC();
  5. SAVE_HOOK = null;
  6. System.gc();
  7. Thread.sleep(500);
  8. if (null != SAVE_HOOK) { //此时对象应该处于(reachable, finalized)状态
  9. System.out.println("Yes , I am still alive");
  10. } else {
  11. System.out.println("No , I am dead");
  12. }
  13. SAVE_HOOK = null;
  14. System.gc();
  15. Thread.sleep(500);
  16. if (null != SAVE_HOOK) {
  17. System.out.println("Yes , I am still alive");
  18. } else {
  19. System.out.println("No , I am dead");
  20. }
  21. }
  22. @Override
  23. protected void finalize() throws Throwable {
  24. super.finalize();
  25. System.out.println("execute method finalize()");
  26. SAVE_HOOK = this;
  27. }
  28. }
 

静态方法被null调用,为何不报NullPointerException?

解释:

原因就是,这里调用的方法是类中声明的静态方法,也就是类方法,类方法是属于类的。通常使用类作为调用者来调用类方法,但我们也可以使用对象来调用类方法,其效果与通过类调用完全一样。当使用实例来调用类方法时,实际上依然是委托给该类来访问类成员,因此即使某个实例为null,它也可以访问它所属类的的类成员,而不发生空指针异常。

public class FinalizeTest {
public static FinalizeTest finalizeTest;
@Override
protected void finalize() throws Throwable {
System.out.println("finalized");
finalizeTest=this;
}
public static void main(String[] args) {
FinalizeTest f = new FinalizeTest();
System.out.println("first print "+f);
f = null;
System.gc();
System.out.println("second print "+f);
// System.out.println(f.finalizeTest);
System.out.println(f.name);
}
} 结果可能是 也可能是别的

first print FinalizeTest@685f4c2e
second print null
null
finalized

加入以下代码
System.gc();
try
{
Thread.currentThread().sleep(1000);
}
catch(Exception ex)
{
ex.printStackTrace();
} 结果是

first print FinalizeTest@685f4c2e
finalized
second print null
FinalizeTest@685f4c2e

finalize的作用的更多相关文章

  1. Java finalize方法使用

    <JAVA编程思想>: Java提供finalize()方法,垃圾回收器准备释放内存的时候,会先调用finalize(). (1).对象不一定会被回收. (2).垃圾回收不是析构函数. ( ...

  2. java finalize方法总结、GC执行finalize的过程

    注:本文的目的并不是鼓励使用finalize方法,而是大致理清其作用.问题以及GC执行finalize的过程. 1. finalize的作用 finalize()是Object的protected方法 ...

  3. java的finalize方法使用

    1. finalize的作用 finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法. finalize()与C++中的析构函数 ...

  4. java---final、finally、finalize的区别

    Java finalize方法使用 标签: javaappletobjectwizardjvm工作 2011-08-21 11:37 48403人阅读 评论(5) 收藏 举报  分类: Java(96 ...

  5. Android内存优化4 了解java GC 垃圾回收机制2 GC执行finalize的过程

    1. finalize的作用 finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法. finalize()与C++中的析构函数 ...

  6. [java]final关键字、finally关键字与finalize()方法

    final关键字: final关键字通常指的是“无法改变的”,使用“无法改变”这样修饰可能出于两个原因:设计或者效率. final可以修饰变量.方法和类. 一.final变量 一个既是static又是 ...

  7. finalize方法

    什么是垃圾回收机制 不定时去堆内存中清理不可达对象.不可达的对象并不会马上就会直接回收, 垃圾收集器在一个Java程序中的执行是自动的,不能强制执行,即使程序员能明确地判断出有一块内存已经无用了,是应 ...

  8. 关于finalize()

    finalize()是Object中的方法,当垃圾回收器将要回收对象所占内存之前被调用,即当一个对象被虚拟机宣告死亡时会先调用它finalize()方法,让此对象处理它生前的最后事情(这个对象可以趁这 ...

  9. 看完这篇 final、finally 和 finalize 和面试官扯皮就没问题了

    我把自己以往的文章汇总成为了 Github ,欢迎各位大佬 star https://github.com/crisxuan/bestJavaer 已提交此篇文章 final 是 Java 中的关键字 ...

随机推荐

  1. 常用的HTTP请求头与响应头

    HTTP消息头是指,在超文本传输协议( Hypertext Transfer Protocol ,HTTP)的请求和响应消息中,协议头部分的那些组件.HTTP消息头用来准确描述正在获取的资源.服务器或 ...

  2. HDU 6667 Roundgod and Milk Tea (思维)

    2019 杭电多校 8 1011 题目链接:HDU 6667 比赛链接:2019 Multi-University Training Contest 8 Problem Description Rou ...

  3. 2019秋第一次Java学习总结

    本周Java学习总结: 知识点总结: 1.Java中程序的执行步骤 使用Javac将一个.Java源文件编译成.class文件 使用Java可以执行一个*.class文件 2.&&与& ...

  4. erlang在windows下和虚拟机节点通信

    版权声明:博客将逐步迁移到 http://cwqqq.com https://blog.csdn.net/cwqcwk1/article/details/24738599 在Linux下部署erlan ...

  5. idea使用tomcat运行maven打包的war

    注:此方法启动的tomcat只能够访问到本项目,包括tomcat的ROOT目录都访问不到 1.点击添加run  config ,选择添加tomcat  server

  6. C语言指针函数和函数指针

    #include <stdio.h> char *test(); void test1(); int main() { /********************************* ...

  7. selenium如何操作页面树状列表

    selenium如何操作页面树状列表??举个例子:我要怎么操作如下图所示的树状结构列表?我要对这个树状结构列表做什么操作? 一.思路 1.根据driver.find_element_by_xpath( ...

  8. vue 学习四 了解组件

    1组件的注册 全局注册 import Vue from 'vue'; import com from './component1'; Vue.component("com_name" ...

  9. leetcode-52-N皇后②

    题目描述: 方法一:回溯 class Solution: def totalNQueens(self, n: int) -> int: def backtrack(i,tmp,col,z_dia ...

  10. cocos2D-X 常见49种Action

    bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !CCLayer::init( ...