java对象生命周期和类生命周期

java对象生命周期

对象的整个生命周期大致可以分为7个阶段:创建阶段(Creation)、应用阶段(Using)、不可视阶段(Invisible)、不可到达阶段(Unreachable)、可收集阶段(Collected)、终结阶段(Finalized)与释放阶段(Free)。

创建阶段

一个Java类(除Object类外)至少有一个父类(Object),这个规则既是强制的,也是隐式的。你可能已经注意到在创建一个Java类的时候,并没有显式地声明扩展(extends)一个Object父类。

public class A { 
     … 
} 
这个声明等同于下面的声明: 
public class A extends java.lang.Object { 
     … 
} 

创建对象时应该遵循的规则

避免在循环体中创建对象,即使该对象占用内存空间不大。

… … 
for (int i = 0; i < 10000; ++i) { 
    Object obj = new Object(); 
    System.out.println("obj= "+ obj); 
} 
… … 

上面这种写法违法了该规则,会浪费大量空间。

… … 
Object obj = null; 
for (int i = 0; i < 10000; ++i) { 
    obj = new Object(); 
    System.out.println("obj= "+ obj); 
} 
… … 

这种写法,仅在内存中保存一份对该对象的引用,而不像上面的第一种编写方式中代码会在内存中产生大量的对象应用,浪费大量的内存空间,而且增大了系统做垃圾回收的负荷。

不要对一个对象进行多次初始化,这同样会带来较大的内存开销,降低系统性能。

应用阶段

强引用

强引用(Strong Reference)是指JVM内存管理器从根引用集合(Root Set)出发遍寻堆中所有到达对象的路径。当到达某对象的任意路径都不含有引用对象时,对这个对象的引用就被称为强引用。

软引用

软引用(Soft Reference)的主要特点是具有较强的引用功能。只有当内存不够的时候,才回收这类内存,因此在内存足够的时候,它们通常不被回收。

… … 
import java.lang.ref.SoftReference; 
… 
A a = new A(); 
… 
// 使用 a 
… 
// 使用完了a,将它设置为soft 引用类型,并且释放强引用; 
SoftReference sr = new SoftReference(a); 
a = null; 
… 
// 下次使用时 
if (sr!=null) { 
     a = sr.get(); 
} 
else{ 
     // GC由于内存资源不足,可能系统已回收了a的软引用, 
     // 因此需要重新装载。 
     a = new A(); 
     sr=new SoftReference(a); 
} 

弱引用

GC在进行回收时,需要通过算法检查是否回收Soft引用对象,而对于Weak引用对象, GC总是进行回收。因此Weak引用对象会更容易、更快被GC回收。

… … 
import java.lang.ref.WeakReference; 
… 
A a = new A(); 
… 
// 使用 a 
… 
// 使用完了a,将它设置为weak 引用类型,并且释放强引用; 
WeakReference wr = new WeakReference (a); 
a = null; 
… 
// 下次使用时 
if (wr!=null) { 
    a = wr.get(); 
} 
else{ 
    a = new A(); 
    wr = new WeakReference (a); 
} 
… … 

虚引用

虚引用(Phantom Reference)的用途较少,主要用于辅助finalize函数的使用。Phantom对象指一些执行完了finalize函数,并且为不可达对象,但是还没有被GC回收的对象。

不可视阶段

… … 
public void process () { 
    try { 
         Object obj = new Object(); 
         obj.doSomething(); 
     } catch (Exception e) { 
     e.printStackTrace(); 
     } 
     while (isLoop) { // ... loops forever 
      // 这个区域对于obj对象来说已经是不可视的了 
         // 因此下面的代码在编译时会引发错误 
         obj.doSomething();  
     } 
} 
… … 

如果一个对象已使用完,而且在其可视区域不再使用,此时应该主动将其设置为空(null)。可以在上面的代码行obj.doSomething();下添加代码行obj = null;,这样一行代码强制将obj对象置为空值。这样做的意义是,可以帮助JVM及时地发现这个垃圾对象,并且可以及时地回收该对象所占用的系统资源。

不可到达阶段

在虚拟机所管理的对象引用根集合中再也找不到直接或间接的强引用,这些对象通常是指所有线程栈中的临时变量,所有已装载的类的静态变量或者对本地代码接口(JNI)的引用。这些对象都是要被垃圾回收器回收的预备对象,但此时该对象并不能被垃圾回收器直接回收。其实所有垃圾回收算法所面临的问题是相同的——找出由分配器分配的,但是用户程序不可到达的内存块。

可收集阶段、终结阶段与释放阶段

  • 垃圾回收器发现该对象已经不可到达。
  • finalize方法已经被执行。
  • 对象空间已被重用。

当对象处于上面的三种情况时,该对象就处于可收集阶段、终结阶段与释放阶段了。虚拟机就可以直接将该对象回收了。

java类生命周期

一个java类的完整的生命周期会经历加载、连接、初始化、使用、和卸载五个阶段

jvm(java虚拟机)中的几个比较重要的内存区域

  • 方法区:在java的虚拟机中有一块专门用来存放已经加载的类信息、常量、静态变量以及方法代码的内存区域,叫做方法区。
  • 常量池:常量池是方法区的一部分,主要用来存放常量和类中的符号引用等信息。
  • 堆区:用于存放类的对象实例。
  • 栈区:也叫java虚拟机栈,是由一个一个的栈帧组成的后进先出的栈式结构,栈桢中存放方法运行时产生的局部变量、方法出口等信息。当调用一个方法时,虚拟机栈中就会创建一个栈帧存放这些数据,当方法调用完成时,栈帧消失,如果方法中调用了其他方法,则继续在栈顶创建新的栈桢。

初始化

如果一个类被直接引用,就会触发类的初始化。在java中,直接引用的情况有:

  • 通过new关键字实例化对象、读取或设置类的静态变量、调用类的静态方法。
  • 通过反射方式执行以上三种行为。
  • 初始化子类的时候,会触发父类的初始化。
  • 作为程序入口直接运行时(也就是直接调用main方法)。
  • 除了以上四种情况,其他使用类的方式叫做被动引用,而被动引用不会触发类的初始化。

卸载

在类使用完之后,如果满足下面的情况,类就会被卸载:

  • 该类所有的实例都已经被回收,也就是java堆中不存在该类的任何实例。
  • 加载该类的ClassLoader已经被回收
  • 该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法

你可能感兴趣的:(语言)