对象引用应用程序设计接口是JDKTM1.2中新定义的。该应用程序设计接口答应应用程序以对象引用的方式与JVM的内存治理器进行交互。当应用程序需治理大量内存对象或者在新的java对象创建之前需删除原有对象时,Java对象引用应用程序设计接口具有相当大的用途,例如:
● 基于Web的应用程序经常要求显示大量图片,当用户离开某一Web页时,往往不能确定是否能够顺利的返回。在这种程序中,应用Java对象引用API可以创建这样一个环境,即当堆内存以最小程度运行时,内存治理器创建对象。当用户返回时,应用程序就会重新载入已经创建的图片。
● 应用对象引用队列可以创建这样一个环境,当通过对象引用获得某一对象时,应用程序得到通知。然后,应用程序就可以对相关对象进行清除操作,同时使这些对象在内存治理器中合法化。
内存治理器的工作机制
下面将首先介绍未嵌入引用对象时内存治理器的工作机制,然后讨论引用对象加入之后Java堆发生的变化。
内存治理器的作用就是识别程序中不再使用的对象,并且回收其内存。
一个Java应用程序由一系列线程组成,每个线程执行一系列方法,而每个方法通过参数或局部变量来引用对象。这些引用属于引用集合中的一部分,直接进入应用程序。另外,引用集合中还包括类库中定义的静态引用变量,以及通过Java本地接口(JNI)API获得的引用。引用集合中的所有引用对象都可以被当前应用程序获取,而不必被回收。同样地,这些对象可能包含对其它对象的引用,也可以被应用程序获取,依此类推。Java堆中的其它对象视为不可获取的,而所有这些不可获取的对象在内存治理中也是合法的。假如一个不可获取的对象使用finalize()方法,任务就交给了对象所调用的收尾器(finalizer)。在内存回收期间,不具有收尾器的不可获取对象和已经调用收尾器的对象被简单回收。
内存回收的算法是不断变化的,共性的方面是从引用集合中识别可获取的对象以及回收被其它对象占据的内存空间。
加入引用对象之后的引用与常规引用的区别在于,引用对象中的引用专门由内存治理器来处理。引用对象封装了其它一些对象的引用,我们称之为指示对象。在引用对象创建的同时,也就定义了该引用对象的指示对象。
Java对象引用
图1所示为对象引用应用程序设计接口中定义的类层次。其中SoftReference类、WeakReference类和PhantomReference类中分别定义了三种引用对象以及相应的三种获取对象的能力。因此按照由强到弱,对象可获取程度可划分为如下五种类型:强获取(strongly reachable)、次获取(softly reachable)、弱获取(weakly reachable)、虚获取(phantomly reachable)和不可获取(unreachable)。
图1 对象应用类层次
根据应用程序要求,对象可以是强引用(strong references)、次引用(soft references)、弱引用(weak references)、虚引用(phantom references)的任意组合。为了确定对象的可获取程度,JVM内存治理器从引用集合出发遍寻堆中所有到对象的路径。当到达某对象的任意路径都不含有引用对象时,则称该对象具有强获取能力;当路径中含有一个或几个引用对象时,根据内存治理器所查询的引用对象的类型分别归为次获取、弱获取、虚获取。
另外,对象引用API中还定义了引用对象队列(java.lang.ref.ReferenceQueue),这是内存治理器对引用对象进行治理的一种简单数据结构。值得注重的是,在进行引用对象定义时,要求phantom reference对象必须产生于一个引用对象队列,而soft reference和weak reference对象则无此限制,如:
ReferenceQueue queue = new ReferenceQueue();
PhantomReference PR = new PhantomReference(object, queue);
Soft References 应用实例
下面以在基于web的应用程序中使用soft references为例,来说明Java对象引用与JVM的内存治理器进行交互的原理。
当用户打开某一web页时,applet代码获得图片并且得到显示。假如在代码中同时创建了该图片对象的soft references,那么当用户离开该web页时,内存治理器对图片所分配的内存是否回收做出选择。当用户返回该web页时,在applet代码中使用SoftReference.get方法就会得到图片才内存中是否仍存在的消息。假如在内存治理器中未创建该图片,在web页上会很快得到显示;否则,applet代码就会重新获取。
下面是Example.java的完整源代码。
import java.awt.Graphics;
import java.awt.Image;
import java.applet.Applet;
import java.lang.ref.SoftReference;
public class Example extends Applet {
SoftReference sr = null;
public void init() {
System.out.println("Initializing");
}
public void paint(Graphics g) {
Image im = (sr == null) ? null : (Image)(sr.get());
if (im == null) {
System.out.println("Fetching image");
im = getImage(getCodeBase(),"yundong.gif");
sr = new SoftReference(im);
}
System.out.println("Painting");
g.drawImage(im, 25, 25, this);
g.drawString("运动之美",20,20);
im = null;
/* Clear the strong reference to the image */
}
public void start() {
System.out.println("Starting");
}
public void stop() {
System.out.println("Stopping");
}
}
在上面的代码中,对象image是一个图片对象,传递给一个SoftReference对象sr。