您的位置:首页 > 编程语言 > Java开发

Java虚拟机之对象的生命周期

2013-01-26 15:51 344 查看
       要在JVM的堆中创建某类型的实例化对象,必须先完成该类型的加载、连接和初始化。因此,对象的生命周期只是类生命周期中的使用阶段,而类的生命周期要比对象的生命周期要长。对象的生命周期开始于类的实例化,中间经历使用阶段,结束于对象的垃圾收集。下面主要介绍对象生命周期中的这三个阶段。

1. 类实例化

    Java程序中,类可以被显式或者隐式地实例化。

    显式实例化的4种途径:

使用new操作符
使用反射,调用java.lang.Class或java.lang.reflect.Constructor的newInstance()方法
使用现有对象的clone()方法
使用反序列化手段,调用java.io.ObjectInputStream的readObject()方法

    隐式实例化的方法:

Java的每个命令行参数都会创建相应的String对象,并把它们组织成String数组作为一个参数传递给程序入口main(String args[])方法
JVM装载的每个类型,都会隐式地创建描述该类型的Class实例
字符串常量对应一个String对象
字符串操作符“+”的运算结果如果不是编译时常量,会创建一个String对象

    无论采用哪种方式实例化对象,JVM创建对象的步骤如下:

    1) 在堆中为对象分配内存

    2) 实例变量初始化为默认值

    3) 对象初始化,给实例变量赋正确的初始值

 

       Java编译器在编译每个类时都会为该类至少生成一个实例初始化方法——即“<init>()”方法。此方法与源代码中的每个构造方法相对应。如果类没有明确地声明任何构造方法,编译器则为该类生成一个默认的无参构造方法,这个默认的构造器仅仅调用父类的无参构造器,与此同时也会生成一个与默认构造方法对应的“ <init>()”方法。

      <init>()方法内可能包括的代码内容大概为:调用另一个<init>()方法;对实例变量初始化;与其对应的构造方法内的代码。
      如果构造方法是明确地从调用同一个类中的另一个构造方法(一个this()调用)开始,那它对应的<init>()方法体内包括的内容为:一个同类的<init>()方法的调用;对应用构造方法内的所有字节码。
      如果构造方法不是通过调用自身类的其它构造方法开始,并且该对象不是Object对象,那<init>()方法内则包括的内容为:一个对父类<init>()方法的调用;对实例变量初始化方法的字节码;最后是对应构造子的方法体字节码。

      如果构造方法不是通过调用自身类的其它构造方法开始,并且这个类是Object,那么它的<init>()方法则不包括对父类<init>()方法的调用。

      如果构造方法通过明确地调用超类的构造方法(一个super()调用)开始,那它对应的<init>()方法会调用对应的超类的<init>()方法。

      如果构造方法没有明确地从this()或者super()调用开始,对应的<init>()方法默认会调用超类的无参数<init>()方法。

2. 对象使用

      Java中是通过引用来使用对象。在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。其中,强引用是应用最普遍的引用。

      java.lang.ref.Reference类的三个直接子类:SoftReference、WeakReference和PhantomReference,分别对应着可触及状态的三个比较弱的形式:软引用、弱引用和虚引用。强引用与较弱形式的引用的最基本区别是:强引用禁止引用目标被垃圾收集器回收,而较弱形式的引用不禁止。创建软引用、弱引用和虚引用,只需要简单地把强引用传递到对应的引用对象的构造方法中。下面介绍一下4种级别的引用的特点。

强引用

     如果一个对象具有强引用,垃圾收集器绝不会回收它。当内存空间不足,JVM宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会考随意回收具有强引用的对象来解决内存不足的问题。

软引用

     如果一个对象具有软引用,当内存空间足够时,垃圾收集器不会回收它;当内存不足时,就会回收这些对象的内存。只要垃圾收集器没有回收它,该对象就可以被程序使用。因此,软引用可用来实现内存敏感的高速缓存。

弱引用

     如果一个对象具有弱引用,当垃圾收集器发现只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾收集器是一个优先级很低的线程,因此不一定会很快发现只具有弱引用的对象。

虚引用

     虚引用不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾收集器回收。虚引用主要用来跟踪对象被垃圾回收的活动。

3. 垃圾收集

      程序可以显式或者隐式地为对象分配内存,但是不能明确地释放内存。当一个对象不再被程序所引用时,JVM会通过垃圾收集器回收该对象的内存空间。

      如果类声明一个返回值为void的finalize()方法,垃圾收集器会在释放这个类的实例对象所占内存之前执行这个方法一次。由于finalize()方法是一个普通的Java方法,它可以直接被程序所调用。这样的直接调用不会影响垃圾收集器的自动调用过程。垃圾收集器最多只会调用一次对象的finalize()方法。如果finalize()方法执行后,对象重新被引用,随后再次变得不被引用,垃圾收集器不会第二次调用finalize()方法。

     finalize()方法具有如下特点:

垃圾收集器何时执行该方法是不确定的
finalize()方法可能使对象复活
垃圾收集器自动调用finalize()方法抛出的任何异常都将被忽略

     在垃圾收集器看来,堆中的对象都处于三种状态之一:

可触及:可以从根节点开始通过追踪“触及”到该对象;
可复活:从根节点开始的追踪图中不可触及,但是可能在垃圾收集器执行某些终结方法时触及;
不可触及:从根节点开始的追踪图中不可触及,同时不可能通过任何终结方法复活。垃圾收集器只回收该状态下的对象。

    垃圾收集器的具体回收策略,可以看之前的博客:

Java虚拟机之垃圾回收 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息