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

JAVA对象引用与垃圾收集

2006-09-09 18:04 585 查看
影子引用
java.lang.ref.PhantomReference
Phantom Reference 主要是用来取代对象的 finalize()。程序员利用 finalize() 来进行释放资源的同时,有可能不小心 让此对象再度拥有 Direct Reference。但是使用 Phantom Reference 则不会有此情形发生。和 Weak Reference 以 及 SoftReference 最大的不同是:Phantom Reference 一订要搭配着 ReferenceQueue 使用,因为 Phantom Reference 的 get() 传 出值一定是 null(以避免此对象不小心再度拥有 Direct Reference)。通常我们会设计一个 class 继承 PhantomReference,然 后 override 其 clear() 来定义释放资源等收尾的动作。当然,我宁可小心一点地使用 finalize(),也不愿意自找麻烦地使用 Phantom Reference。
弱引用
java.lang.ref.WeakReference
不过,现在有了 Weak Reference 之后,这就可以迎刃而解了。如果你希望能随时取得某对象的信息,但又不想影响此 对象的垃圾收集,那么你应该用 Weak Reference 来记住此对象,而不是用一般的 reference。请看下面的例子:
  WeakReference wr = new WeakReference(obj);
  if (wr.get()==null) {
    System.out.println("obj 已经被清除了 ");
  } else {
  System.out.println("obj 尚未被清除,其信息是 "+obj.toString());
}
这类的技巧,在设计 Optimizer 或 Debugger 这类的程序时常会用到,因为这类程序需要取得某对象的信息,但是不可以 影响此对象的垃圾收集。
java.lang.ref.SoftReference
  所有Soft Reference到的对象保证会在java虚拟机发生OutOfMemoryError 前被清除。Soft Reference 虽然和 Weak Reference 很类似,但是用途却不同。SoftReference 常被用来实现 object-cache (memory-sensitive caches)之用的。 被 Soft Reference 指到的对象,即使没有任何 Direct Reference,也不会被清除。一直要到 JVM 内存不足时且 没有 Direct Reference 时才会清除,如此一来 SoftReference 不但可以把对象 cache 起来,也不会造成内存不足的错误 (OutOfMemoryError)。
public(公众) class ReferenceQueue

extends(扩充) Object

Reference(提及) queues(行列), to which registered(已注册的) reference objects are appended(附加) by the garbage(垃圾) collector(收藏家) after the appropriate(适当的) reachability changes(改变) are detected(检测到的).

[align=left]WeakHashMap类
  由于作为key的对象将通过计算其散列函数来确定与之对应的value的位置,因此任何作
为key的对象都必须实现hashCode和equals方法。hashCode和equals方法继承自根类Object
,如果你用自定义的类当作key的话,要相当小心,按照散列函数的定义,如果两个对象相
同,即obj1.equal
s(obj2)=true,则它们的hashCode必须相同,但如果两个对象不同,则它们的hashCode不一
定不同,如果两个不同对象的hashCode相同,这种现象称为冲突,冲突会导致操作哈希表的
时间开销增大,所以尽量定义好的hashCode()方法,能加快哈希表的操作。[/align]
[align=left]  如果相同的对象有不同的hashCode,对哈希表的操作会出现意想不到的结果(期待的
get方法返回null),要避免这种问题,只需要牢记一条:要同时复写equals方法和
hashCode方法,而不要只写其中一个。
  Hashtable是同步的。[/align]
Transient 表明的实体可以在序列化时忽落。.transient只能用在类的成员变量上,不能用在方法里
transient变量不能是final和static的
Volatile 表明变量是被几个线程同时修改的
如何用this呢?请看:
class Outer{
int i;
class Inner{
class InnerInner{
void Test(){
Outer.this.i=1;
}
}
}
}
意思是FP-stct,在Java虚拟机进行浮点运算时,如果没有指定stctfp关键字时,Java的编译器以及运行环境在对浮点运算的表达式是采取一种近似于我行我素的行为来完成这些作,以致于得到的结果往往无法令你满意.而一旦使用了stctfp来声明一个类、接口或者方法时,那么所声明的范围内Java的编译器以及运行环境会完全依照浮点规范IEEE-754来执行.因此如果你想让你的浮点运算更加精确,而且不会因为不同的硬件平台所执行的结果不一致的话,那就请用关键字

对象引用应用程序设计接口是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。其中image对象是sr的指示对象,sr中的引用域是从次引用(soft reference)到 image。
  
  Weak References分析
  
  对于一个稳定的对象,比如说线程类对象,当需要获取外部数据时,在程序中应用weak references是非常理想的。如果利用引用队列创建了某一线程的weak reference,那么当线程不再具有强获取能力时,应用程序得到通知,根据此通知,应用程序才能执行相关数据对象的清除工作。
  
  当内存管理器未发现strong references 和 soft references 时,我们称对象具有弱获取能力,即在到达该对象的路径中至少包含一个weak reference。程序中weak references被清除一段时间后,弱获取对象被收尾器收集。由此也可以看出,soft reference和weak reference之间的区别在于,应用soft reference时,内存管理器利用算法决定是否创建弱获取对象,而应用weak reference时,内存管理器必须创建次获取对象。
  
  引用对象链
  
  当到达某一对象的路径中含有多个引用对象时,就构成了引用对象链。内存管理器按照由强到弱的顺序处理引用对象,具体处理步骤包括:Soft references、 Weak references、Finalization、Phantom references和创建对象五个部分。
  
  当内存管理器未发现前三种对象引用时,我们称对象具有虚获取能力,即在到达该对象的路径中至少包含一个phantom reference。虚引用对象直接被收尾器收集,而不被重新创建。当内存管理器发现只有phantom references时,对象就将处于等候phantom reference状态,应用程序向引用队列发出通知,然后对虚引用对象调用clear()方法,将其引用域设置为null,最后对不可获取对象执行收集清除处理任务。
  
  通常,对象所具有的获取能力与引用对象集合直接路径中的最弱连接者相同。据此可以看出:
  
  图2(a)中,虚引用对象具有强获取能力,其它对象均具虚获取能力;
  
  (b)中虚引用对象和弱引用对象均具强获取能力,故次引用对象和对象集合具有若获取能力;
  
  (c)中虚引用对象、弱引用对象和次引用对象均具强获取能力,那么对象集合则具次获取能力。
  

 
  图2 引用对象链
  小结
  ● 引用对象API是Java2平台中的特色之一。
  
  ● 在程序中使用引用对象API不但可以在一定程度上控制内存管理器,实现内存自动管理,还可以提高程序的稳定性和安全性。
  
  ● 引用对象链中各个对象的获取能力与整个链相关。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: