GC,Reference,Finalize,Dispose
Java提供了垃圾对象自动回收(GC)机制,该机制对堆heap里的对象就其被引用情况进行跟踪判断,对合适对象进行自动回收释放内存。按java规范,对象分如下引用情况:
An object is strongly reachable if it can be reached by some thread without traversing any reference objects. A newly-created object is strongly reachable by the thread that created it.
An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference.
An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference. When the weak references to a weakly-reachable object are cleared, the object becomes eligible for finalization.
An object is phantom reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it.
Finally, an object is unreachable, and therefore eligible for reclamation, when it is not reachable in any of the above ways.
根据引用情况不同,GC处理过程也不同。
当一个对象实例不被强引用strongly reachable时,GC的某次运行就有可能扫描到该对象。这时GC会检查该对象是否softreference reachable,如果是,则尽可能放它一马,一笑而过,但如果放过去就会引起out of memory error,则就要处理该对象。处理过程首先要检查是否实现了finalize方法的对象,如果是则标记finalizable,并导致Finalizer系统线程(setDaemon(true),Thread.MAX_PRIORITY - 2)在后续巡检中对此对象调用finalize方法。执行完finalize方法后如果在此后某次的GC运行中再次被发现softreference reachable,则此时导致clear softreference,并释放内存,最后归到softreference-queue中。
如果本对象没有实现finalize方法,则GC省去其对应处理环节。
此过程同样适用于weakreference reachable,所不同的是GC将不会尽可能放过该对象。
对于PhantomReference reachable,情况不同之处在于PhantomReference reachable定义在finalize已经执行结束后的GC的某次运行时,这个时候,它不去PhantomReference clear,也不释放内存,而是直接归到PhantomReference-queue中,此后需要应用程序自行clear才能释放,这也是PhantomReference一定要求queue的原因。
基于此GC机制,对“实现当不使用某对象时释放其附属资源”这样的需求,java提供两种实现方式。
Finalize方式就是指Object class的那个Finalize方法,可以被任何class进行override来实现释放对应附属资源。由于历史原因,执行该finalize方法的Finalizer线程保留为一个低优先级线程,因此导致获得巡检机会从而进行资源释放将不是十分及时;另外,java规范允许在finalize方法中再次使该对象恢复强引用,因而GC总是在执行finalize后的再次运行中才考虑释放该对象的内存,如果该对象本身占用内存比较大,这样同样导致整体资源释放将不是十分及时。最后,如果一个class实现了finalize方法,不仅如上所述释放其实例时比较占用机器资源,建立实例的过程也将因要通过必须的finalize方法检测及底层register而占用额外的资源。为此,java提供了Dispose模式可以用来替代finalize模式。
Dispose方式的实现就不在class里实现finalize方法了。在jre中,已经为java2D的支持实现了一个Disposer用来帮助释放对象附用的图形资源,下面以此为例说明Dispose方式。
sun.java2d.Dispose随着类加载初始化构建一个Java2D Disposer线程(setDaemon(true),Thread.MAX_PRIORITY),同时该类对外提供public static addRecord(Object target, DisposerRecord rec)用来建立对指定target的weakreference或 PhantomReference(系统属性sun.java2d.reftype指定)监测。当指定对象target失去强引用而成为weakreference或PhantomReference reachable时,会被GC及时置入reference-queue中,同时被高优先级的本Java2D Disposer线程及时监测到,然后本线程会去从reference-queue中拿到此reference,并通过内部映射表hashtable找到当初addRecord时传入的DisposerRecord,并调用其dispose()。所以在该dispose方法中实现释放附属资源的逻辑就可以了。
Java提供了垃圾对象自动回收(GC)机制,该机制对堆heap里的对象就其被引用情况进行跟踪判断,对合适对象进行自动回收释放内存。按java规范,对象分如下引用情况:
An object is strongly reachable if it can be reached by some thread without traversing any reference objects. A newly-created object is strongly reachable by the thread that created it.
An object is softly reachable if it is not strongly reachable but can be reached by traversing a soft reference.
An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference. When the weak references to a weakly-reachable object are cleared, the object becomes eligible for finalization.
An object is phantom reachable if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it.
Finally, an object is unreachable, and therefore eligible for reclamation, when it is not reachable in any of the above ways.
根据引用情况不同,GC处理过程也不同。
当一个对象实例不被强引用strongly reachable时,GC的某次运行就有可能扫描到该对象。这时GC会检查该对象是否softreference reachable,如果是,则尽可能放它一马,一笑而过,但如果放过去就会引起out of memory error,则就要处理该对象。处理过程首先要检查是否实现了finalize方法的对象,如果是则标记finalizable,并导致Finalizer系统线程(setDaemon(true),Thread.MAX_PRIORITY - 2)在后续巡检中对此对象调用finalize方法。执行完finalize方法后如果在此后某次的GC运行中再次被发现softreference reachable,则此时导致clear softreference,并释放内存,最后归到softreference-queue中。
如果本对象没有实现finalize方法,则GC省去其对应处理环节。
此过程同样适用于weakreference reachable,所不同的是GC将不会尽可能放过该对象。
对于PhantomReference reachable,情况不同之处在于PhantomReference reachable定义在finalize已经执行结束后的GC的某次运行时,这个时候,它不去PhantomReference clear,也不释放内存,而是直接归到PhantomReference-queue中,此后需要应用程序自行clear才能释放,这也是PhantomReference一定要求queue的原因。
基于此GC机制,对“实现当不使用某对象时释放其附属资源”这样的需求,java提供两种实现方式。
Finalize方式就是指Object class的那个Finalize方法,可以被任何class进行override来实现释放对应附属资源。由于历史原因,执行该finalize方法的Finalizer线程保留为一个低优先级线程,因此导致获得巡检机会从而进行资源释放将不是十分及时;另外,java规范允许在finalize方法中再次使该对象恢复强引用,因而GC总是在执行finalize后的再次运行中才考虑释放该对象的内存,如果该对象本身占用内存比较大,这样同样导致整体资源释放将不是十分及时。最后,如果一个class实现了finalize方法,不仅如上所述释放其实例时比较占用机器资源,建立实例的过程也将因要通过必须的finalize方法检测及底层register而占用额外的资源。为此,java提供了Dispose模式可以用来替代finalize模式。
Dispose方式的实现就不在class里实现finalize方法了。在jre中,已经为java2D的支持实现了一个Disposer用来帮助释放对象附用的图形资源,下面以此为例说明Dispose方式。
sun.java2d.Dispose随着类加载初始化构建一个Java2D Disposer线程(setDaemon(true),Thread.MAX_PRIORITY),同时该类对外提供public static addRecord(Object target, DisposerRecord rec)用来建立对指定target的weakreference或 PhantomReference(系统属性sun.java2d.reftype指定)监测。当指定对象target失去强引用而成为weakreference或PhantomReference reachable时,会被GC及时置入reference-queue中,同时被高优先级的本Java2D Disposer线程及时监测到,然后本线程会去从reference-queue中拿到此reference,并通过内部映射表hashtable找到当初addRecord时传入的DisposerRecord,并调用其dispose()。所以在该dispose方法中实现释放附属资源的逻辑就可以了。