转载请注明出处: Java对象的生命周期 与 垃圾回收 - ITeye博客 - 老Man
创建对象的方式
还有其他一些隐式创建对象的方法:
不管采取哪种方式创建对象,JVM创建一个对象都包含以下步骤:
(1) 给对象分配内存。
(2) 将对象的实例变量自动初始化为其类型的默认值。
(3) 初始化对象,给实例变量赋予正确的初始值。
对于以上第三个步骤,JVM可采用3种方式来初始化对象,到底采用何种初始化方式取决于创建对象的方式。
垃圾回收
Java语言中,内存回收任务由JVM来担当。
在程序的运行环境中,JVM提供了一个系统级的垃圾回收器线程,它负责自动回收那些无用对象所占用的内存。这种内存回收的过程被称为垃圾回收。
垃圾回收具有以下优点:
对象的可触及性
在JVM的垃圾回收器来看。堆区中的每个对象都肯能处于以下三个状态之一:
垃圾回收的时间
当一个对象处于可复活状态时,垃圾回收线程执行它的finalize()方法,任何使它转到不可触及状态,任何回收它占用的内存,这对于程序来说都是透明的。程序只能决定一个对象任何不再被任何引用变量引用,使得它成为可以被回收的垃圾。
类比:居民把无用物品放在指定的地方,清洁工人会把它收拾走。但垃圾被收走的时间,居民是不知道的,也无需了解。
垃圾回收器作为低优先级线程独立运行。在任何时候,程序都无法迫使垃圾回收器立即执行垃圾回收操作。
程序中可调用System.gc()或Runtime.gc()方法提示垃圾回收器尽快执行垃圾回收操作,但是不能保证调用后垃圾回收器会立即执行垃圾回收。
类比:小区垃圾成堆时,居民打电话给环保局,催促清洁工尽快来处理垃圾。但是清洁工不一定立即就来了,也有可能很长时间后再来。
对象的finalize()方法简介
finalize()定义在Object类中:
protected void finalize() throws Throwable
因为该方法为protected,所以任何Java类都可以覆盖finalize()方法,该方法中进行释放对象所占的相关资源的操作。
注意:
JVM的垃圾回收操作对程序来说都是透明的。因此程序无法预料某个无用对象的finalize()方法何时被调用。
finalize()方法的特点:
对象的强,软,弱,虚引用
强引用:
如果一个对象具有强引用,垃圾回收器绝不会回收它。当内存空间不足,JVM宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会考随意回收具有强引用的对象来解决内存不足的问题。
软引用:
如果一个对象具有软引用。如果内存空间足够。垃圾回收器不会回收它。如果内存不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
软引用可用来实现内存敏感的高速缓存。
弱引用:
如果一个对象具有弱引用。当垃圾回收器发现只具有弱引用对象,不管当前内存空间足够与否,都会回收它的内存。
不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现只具有弱引用的对象。
虚引用:
虚引用不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃 圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
下面这个实验代码很好的探究了四种引用级别对垃圾回收的影响
import java.lang.ref.PhantomReference; //虚引用 import java.lang.ref.ReferenceQueue; //引用队列 import java.lang.ref.SoftReference; //软引用 import java.lang.ref.WeakReference; //弱引用 class Obj { private final String name; public Obj(String name) { this.name = name; } @Override protected void finalize() throws Throwable { System.out.println("执行finalize方法"+name); super.finalize(); } } public class Test { public static void main (String[] args) { // hardTest(); // softTest(); // weakTest(); phanTest(); } public static void hardTest() { Obj hard = new Obj("hard"); // hard = null; System.gc(); System.out.println(hard); } public static void softTest() { SoftReference <Obj> soft = new SoftReference<Obj>(new Obj("soft")); System.gc(); System.out.println(soft.get()); } public static void weakTest() { WeakReference <Obj> weak = new WeakReference<Obj>(new Obj("weak")); System.gc(); System.out.println(weak.get()); } public static void phanTest() { ReferenceQueue<Obj> rq = new ReferenceQueue<Obj>(); PhantomReference<Obj> phan = new PhantomReference<Obj>(new Obj("phan"), rq); System.out.println(phan.get()); } }
分别执行四个函数, 并控制强/软引用中的obj是否为null, 共6次实验, 我们可以总结出:
1. 显式的把(强引用)对象置为null,会大大加大 垃圾回收执行频率。几乎只要我们给出建议,jvm就会回收。
2. 对于软引用,如果不显式的置为null的话,和强引用差不多,垃圾回收不会执行。和强引用的区别是:只会等到内存不足的时候才会执行。
3. 对于弱引用,就算你不显式的把他置为null,垃圾回收也会立即执行。
4. 虚引用,相当于null。如果一个对象的虚引用加入了引用队列, 那么这个对象行将就木了