WeakHashMap相关

本文将深入地介绍关于引用对象(Reference Objects)的知识。基本上说,引用对象提供了一种对象间接引用所需内存的方式,这些引用对象保存在一个引用对象中(类ReferenceQuene),它监视这些引用对象使得其可以访问。基于这种类型的引用对象,垃圾回收器能够释放内存,而一般的对象引用则可能无法释放。
在Java中,有四种类型的对象引用。常用的是直接引用,如:
 Object obj = new Object()

您可以将直接引用当作一种无需额外的代码去创建或访问对象的一种强引用。接下来的三种类型的引用是java.lang.ref包中的Reference类的子类。软引用(Soft reference)由SoftReference类提供,弱引用(weak reference)由WeakReference类提供,幻像引用(PhantomReference)由PhantomReference提供。

软引用的工作方式很像数据缓存。当系统内存太低的时候,GC可以任意地释放软引用所引用的对象。换句话说,如果一个对象没有强引用,那么这个对象就是一个候选释放对象。在抛出OutOfMemoryException异常之前,GC将要求释放任何软引用。
 
弱引用比软引用弱。如果对象的引用只有弱引用,则GC将可能在任何时候回收内存,而不需要等到内存不足的时候。典型的动作是GC在下一个回收周期中对象的内存被回收。

幻像引用与清理任务有关。他们提供了一种在GC执行终止程序和释放对象之前即时通知机制。将其理解为在一个对象之前进行的清理任务。

下面是WeakHashMap的一个简单示例。WeakTest程序创建一个WeakHashMap的对象,里面含有一个元素。接着创建了第二个线程等待map清空,要求GC每0.5秒执行一次。主线程等待第二线程完成。

 import java.util.*;

   public class WeakTest {
     private static Map<String, String> map;
     public static void main (String args[]) {
       map = new WeakHashMap<String, String>();
       map.put(new String("Scott"), "McNealey");
       Runnable runner = new Runnable() {
         public void run() {
           while (map.containsKey("Scott")) {
             try {
               Thread.sleep(500);
             } catch (InterruptedException ignored) {
             }
             System.out.println("Checking for empty");
             System.gc();
           }
         }
       };

       Thread t = new Thread(runner);
       t.start();
       System.out.println("Main joining");
       try {
         t.join();
       } catch (InterruptedException ignored) {
       }
     }
   }

因为在map仅有一个键没有强引用,在map中的项会在最近的一个垃圾回收周期内回收。

运行该程序将输出:
 Main joining
 Checking for empty

有两个重要的地方需要指出。第一,正常情况下System.gc()不需要明确地调用。但是因为WeakTest是一个非常轻量级的程序,它不需要使用更多的内存,因此明确地调用垃圾回收机制是必要的。第二,注意到new String("Scott")这一行,你可能会问为什么不直接使用"Scott"而需要new呢?答案是如果你不使用new,那么作为map的键的该字符串在系统的字符串常量池中有一个引用。这将不会移除,所以弱引用也不会释放。为了解决这个问题,需要使用new创建一个特定的引用去引用字符串常量池中的引用。字符串的内容不会重复。它们保留在常量池中。这只是简单地创建了一个单独的指针指向该字符串。
posted @ 2009-03-02 17:37  xiaoyixy  阅读(570)  评论(0编辑  收藏  举报