`
yiliner
  • 浏览: 214769 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

深入理解java的finalize

阅读更多

目录

基本预备相关知识
对象的销毁过程
对象重生的例子
对象的finalize的执行顺序
何时及如何使用finalize
参考

基本预备相关知识

1 java的GC只负责内存相关的清理,所有其它资源的清理必须由程序员手工完成。要不然会引起资源泄露,有可能导致程序崩溃。

2 调用GC并不保证GC实际执行。

3 finalize抛出的未捕获异常只会导致该对象的finalize执行退出。

4 用户可以自己调用对象的finalize方法,但是这种调用是正常的方法调用,和对象的销毁过程无关。

5 JVM保证在一个对象所占用的内存被回收之前,如果它实现了finalize方法,则该方法一定会被调用。Object的默认finalize什么都不做,为了效率,GC可以认为一个什么都不做的finalize不存在。

6 对象的finalize调用链和clone调用链一样,必须手工构造。

Java代码 复制代码
  1. protected void finalize() throws Throwable {   
  2.     super.finalize();   
  3. }  
protected void finalize() throws Throwable {
	super.finalize();
}




对象的销毁过程

在对象的销毁过程中,按照对象的finalize的执行情况,可以分为以下几种,系统会记录对象的对应状态:
unfinalized 没有执行finalize,系统也不准备执行。
finalizable 可以执行finalize了,系统会在随后的某个时间执行finalize。
finalized 该对象的finalize已经被执行了。

GC怎么来保持对finalizable的对象的追踪呢。GC有一个Queue,叫做F-Queue,所有对象在变为finalizable的时候会加入到该Queue,然后等待GC执行它的finalize方法。

这时我们引入了对对象的另外一种记录分类,系统可以检查到一个对象属于哪一种。
reachable 从活动的对象引用链可以到达的对象。包括所有线程当前栈的局部变量,所有的静态变量等等。
finalizer-reachable 除了reachable外,从F-Queue可以通过引用到达的对象。
unreachable 其它的对象。

来看看对象的状态转换图。


好大,好晕,慢慢看。

1 首先,所有的对象都是从Reachable+Unfinalized走向死亡之路的。

2 当从当前活动集到对象不可达时,对象可以从Reachable状态变到F-Reachable或者Unreachable状态。

3 当对象为非Reachable+Unfinalized时,GC会把它移入F-Queue,状态变为F-Reachable+Finalizable。

4 好了,关键的来了,任何时候,GC都可以从F-Queue中拿到一个Finalizable的对象,标记它为Finalized,然后执行它的finalize方法,由于该对象在这个线程中又可达了,于是该对象变成Reachable了(并且Finalized)。而finalize方法执行时,又有可能把其它的F-Reachable的对象变为一个Reachable的,这个叫做对象再生。

5 当一个对象在Unreachable+Unfinalized时,如果该对象使用的是默认的Object的finalize,或者虽然重写了,但是新的实现什么也不干。为了性能,GC可以把该对象之间变到Reclaimed状态直接销毁,而不用加入到F-Queue等待GC做进一步处理。

6 从状态图看出,不管怎么折腾,任意一个对象的finalize只至多执行一次,一旦对象变为Finalized,就怎么也不会在回到F-Queue去了。当然没有机会再执行finalize了。

7 当对象处于Unreachable+Finalized时,该对象离真正的死亡不远了。GC可以安全的回收该对象的内存了。进入Reclaimed。


对象重生的例子

Java代码 复制代码
  1. class C {   
  2.     static A a;   
  3. }   
  4.   
  5. class A {   
  6.     B b;   
  7.   
  8.     public A(B b) {   
  9.         this.b = b;   
  10.     }   
  11.   
  12.     @Override  
  13.     public void finalize() {   
  14.         System.out.println("A finalize");   
  15.         C.a = this;   
  16.     }   
  17. }   
  18.   
  19. class B {   
  20.     String name;   
  21.     int age;   
  22.   
  23.     public B(String name, int age) {   
  24.         this.name = name;   
  25.         this.age = age;   
  26.     }   
  27.   
  28.     @Override  
  29.     public void finalize() {   
  30.         System.out.println("B finalize");   
  31.     }   
  32.   
  33.     @Override  
  34.     public String toString() {   
  35.         return name + " is " + age;   
  36.     }   
  37. }   
  38.   
  39. public class Main {   
  40.     public static void main(String[] args) throws Exception {   
  41.         A a = new A(new B("allen"20));   
  42.         a = null;   
  43.   
  44.         System.gc();   
  45.         Thread.sleep(5000);   
  46.         System.out.println(C.a.b);   
  47.     }   
  48. }  
class C {
	static A a;
}

class A {
	B b;

	public A(B b) {
		this.b = b;
	}

	@Override
	public void finalize() {
		System.out.println("A finalize");
		C.a = this;
	}
}

class B {
	String name;
	int age;

	public B(String name, int age) {
		this.name = name;
		this.age = age;
	}

	@Override
	public void finalize() {
		System.out.println("B finalize");
	}

	@Override
	public String toString() {
		return name + " is " + age;
	}
}

public class Main {
	public static void main(String[] args) throws Exception {
		A a = new A(new B("allen", 20));
		a = null;

		System.gc();
		Thread.sleep(5000);
		System.out.println(C.a.b);
	}
}



期待输出

Java代码 复制代码
  1. A finalize   
  2. B finalize   
  3. allen is 20  
A finalize
B finalize
allen is 20


但是有可能失败,源于GC的不确定性以及时序问题,多跑几次应该可以有成功的。详细解释见文末的参考文档。

对象的finalize的执行顺序

所有finalizable的对象的finalize的执行是不确定的,既不确定由哪个线程执行,也不确定执行的顺序。
考虑以下情况就明白为什么了,实例a,b,c是一组相互循环引用的finalizable对象。

何时及如何使用finalize

从以上的分析得出,以下结论。
1 最重要的,尽量不要用finalize,太复杂了,还是让系统照管比较好。可以定义其它的方法来释放非内存资源。
2 如果用,尽量简单。
3 如果用,避免对象再生,这个是自己给自己找麻烦。
4 可以用来保护非内存资源被释放。即使我们定义了其它的方法来释放非内存资源,但是其它人未必会调用该方法来释放。在finalize里面可以检查一下,如果没有释放就释放好了,晚释放总比不释放好。
5 即使对象的finalize已经运行了,不能保证该对象被销毁。要实现一些保证对象彻底被销毁时的动作,只能依赖于java.lang.ref里面的类和GC交互了。

参考

关于引用类型,GC,finalize的相互交互可以参考ReferenceQueue GC finalize Reference 测试及相关问题

分享到:
评论

相关推荐

    深入理解Java中的final关键字_动力节点Java学院整理

    深入理解 `final` 关键字可以帮助开发者写出更加安全、高效的代码。 首先,`final` 关键字可以用于声明变量。当一个变量被声明为 `final` 时,它的值一旦被赋值后就不能再改变。这适用于成员变量、局部变量以及静态...

    《剑指offer》Java深入理解final、finally、finalize.pdf

    Java编程中的`final`、`finally`和`finalize`关键字对于理解Java程序的运行机制至关重要。它们各自有独特的用途和特点。 首先,`final`关键字是Java中的一个多面手,它可以用于修饰类、方法和变量。当`final`用于...

    深入理解Java虚拟机笔记(带目录).docx

    深入理解 Java 虚拟机笔记 Java 虚拟机(JVM)是 Java 语言的运行环境,它负责解释和执行 Java 字节码。下面是 Java 虚拟机相关的知识点: 虚拟机内存结构 Java 虚拟机的内存结构主要包括以下几个部分: * 方法...

    《深入理解Android》卷Ⅱ

    第2章 深入理解Java Binder和MessageQueue 2.1 概述 2.2 Java层中的Binder架构分析 2.2.1 Binder架构总览 2.2.2 初始化Java层Binder框架 2.2.3 addService实例分析 2.2.4 Java层Binder架构总结 2.3 心系两界...

    Java禁止使用finalize方法共2页.pdf.zip

    本篇文章将深入探讨`finalize()`方法的原理、问题以及替代方案。 1. `finalize()`方法的定义: `finalize()`方法是Java中的一个虚方法,它的设计初衷是为了在对象被垃圾收集器回收前提供最后一次清理机会。程序员...

    一篇文章教你深入理解Java垃圾收集(GC)机制.docx

    Java垃圾收集(GC)机制是Java编程中...理解Java的GC机制有助于优化程序性能,避免因内存管理不当引起的系统不稳定。开发者应根据应用需求选择合适的垃圾收集策略,并注意合理使用各种引用类型,避免不必要的内存占用。

    能让你成为一个优秀的 Java 全栈程序员的系统化系列教程

    深入理解 final、finally、finalize 浅拷贝和深拷贝 关于四种引用类型 Java 开发最容易忽视的 10 个 Bug Java 浅拷贝和深拷贝 Java 创建对象的五种方式 Exception 和 Error 的区别 for 、foreach 、iterator 三种...

    深入探讨 java.lang.ref 包1

    本文将深入探讨这个包中的四种主要引用类型:StrongReference、SoftReference、WeakReference 和 PhantomReference,以及它们的特性、用法和作用。 首先,强引用(StrongReference)是我们在日常编程中最常见的引用...

    理解Java垃圾回收

    理解Java垃圾回收机制对于编写高效、健壮的Java程序至关重要。开发者需要了解垃圾回收的工作原理,避免产生内存泄漏,并合理调整垃圾回收参数以适应应用程序的需求。在实际开发中,结合内存分析工具(如VisualVM、...

    final, finally, finalize的区别

    深入理解这些概念对于编写高效、健壮的Java代码至关重要。 ### final 1. **不可变性**:`final` 关键字用于声明一个变量、方法或类为最终状态,意味着一旦赋值或定义后,其值或状态不能被修改。例如,当一个变量被...

    java初学者必看 java初学者必看

    ### Java初学者必看:深入理解Java垃圾回收机制 对于Java初学者而言,理解Java的垃圾回收机制(Garbage Collection, GC)是非常重要的。在C++等其他编程语言中,程序员需要手动管理内存,比如使用new分配内存后,还...

    Java JDK 6.0 学习笔记.pdf

    例如《Thinking in Java》、《Java核心技术卷》以及Oracle的Java教程,都是深入理解Java的好资源。 通过系统地学习这些知识点,你将能够全面掌握Java JDK 6.0,并为未来的Java开发工作打下坚实的基础。随着技术的...

    【IT十八掌徐培成】Java基础第26天-03.JVM结构-finalize-gc.zip

    Java是世界上最流行的...通过深入理解JVM的结构、`finalize`机制以及GC的工作方式,开发者能够更好地优化Java应用程序的性能,预防和解决内存问题。这不仅是Java程序员的基础知识,也是进阶为高级开发者的关键技能。

    Java基础入门一.pdf

    《Java编程思想》提供了关于对象入门、类继承以及接口等基础和高级特性的讲解,而《深入理解Java虚拟机》则深入讲解了垃圾收集器、内存分配策略以及JVM内部的工作机制。 Spring框架是Java企业级应用开发中最重要的...

    深入理解Java垃圾回收机制以及内存泄漏

    理解Java垃圾回收机制及其与内存泄漏的关系对于编写高效、稳定的Java应用程序至关重要。开发人员应该尽量遵循最佳实践,避免过度依赖垃圾回收,而是积极地管理自己的内存使用,以减少潜在的性能问题和内存泄漏风险。

    深入java虚拟机移植

    ### 深入Java虚拟机移植 #### Java虚拟机概念 Java虚拟机(JVM, Java Virtual Machine)作为Java技术的核心组件之一,在实现Java程序跨平台特性方面扮演着至关重要的角色。它是一种抽象的计算机模型,能够理解并...

    Practical Java(简体中文)

    #### 深入理解Java的关键概念 然而,Java的强大之处并不止于表面,深入到其核心,有诸多隐微细节等待探索。例如,对象创建和初始化过程中的细微差别,如何正确实现`Cloneable`和`Serializable`接口,以及`equals`...

    Java程序员必看的15本书【转】

    8. **《深入理解Java虚拟机》**:周志明的著作,详细解析了JVM的工作原理,包括内存管理、类加载机制、性能优化等。 9. **《Java性能优化权威指南》**:通过实际案例分析Java性能问题,提供了解决方案和调优技巧。 ...

    Java入门--简述Java语言回收机制

    ### Java入门——深入理解Java语言回收机制 #### 一、垃圾回收(Garbage Collection)概述 在编程领域,特别是对于初学者来说,了解并掌握Java的垃圾回收机制是非常重要的。与C++等需要手动管理内存的语言不同,...

Global site tag (gtag.js) - Google Analytics