主要讲解软引用和弱引用的概念以及引用队列的用法,最后介绍了weakhashmap,关于自定义使用软引用结合hashmap构建缓存,可以看参考文章,以后有机会也会专门写一篇介绍。

java中各种引用存活周期

强引用>软引用>弱引用>虚引用。

  • StrongReference-jvm内存不足时也不会回收,直至OOM。
  • SoftReference-jvm进行垃圾回收,内存不足,避免OOM会对软引用的对象进行回收。
  • WeakReference-JVM进行垃圾回收时会回收弱引用,无论内存是否紧张。
  • PhantomReference-任何时候都可能被回收。

软引用和弱引用概念区分

Soft reference objects, which are cleared at the discretion of the garbage collector in response to memory demand. Soft references are most often used to implement memory-sensitive caches.
All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError.

对于软引用因为内存需求会被释放。抛出OOM之前确定所有软引用被释放。

Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed. Weak references are most often used to implement canonicalizing mappings.

对于弱引用gc的时候一定会被释放。

软引用的使用

(使用系统去判断释放时机,而非缓存算法。)

软引用示例

public class SoftReferenceTest
    {

        /**
         * @param args
         */
        public static void main(String[] args)
        {
            //软引用的利用,首先强引用构造软引用,然后强引用放空,使用软引用,软引用为空时重新初始化对象,一种缓存机制
            A a = new A();
            SoftReference<A> sa = new SoftReference<A>(a);
            a = null;

            System.out.println("use a --->");

            //具体使用a对象的时候利用如下代码
            if(sa != null)
            {
                a = (A)sa.get();
            }
            else
            {
                a = new A();
                sa = new SoftReference<A>(a);
            }

            //gc对软引用的影响
            System.out.println("gc effect for softreference");
            System.out.println(sa.get());
            System.gc();
            System.out.println(sa.get()); //由于这里的场景内存不紧张,所以不会回收

            //gc对弱引用的影响
            A b = new A();
            WeakReference<A> sb = new WeakReference<SoftReferenceTest.A>(b);
            b = null;
            System.out.println("gc effect for weakreference");
            System.out.println(sb.get());
            System.gc();
            System.out.println(sb.get());//得到的是null,上一句gc触发垃圾回收,弱引用被释放,调用finalize

        }

        public static class A
        {
            public A()
            {

            }

            @Override
            protected void finalize() throws Throwable
            {
                // TODO Auto-generated method stub
                super.finalize();
                System.out.println("finalize of A" + this.toString());
            }
        }
    }

/*
use a --->
gc effect for softreference
com.bityan.learning.SoftReferenceTest$A@2ce1b3b3
com.bityan.learning.SoftReferenceTest$A@2ce1b3b3
gc effect for weakreference
com.bityan.learning.SoftReferenceTest$A@15128ee5
null
finalize of Acom.bityan.learning.SoftReferenceTest$A@15128ee5
*/

注意,代码调用gc,对于system.gc()使得gc过程在此后一个不固定时间触发,不一定是立即调用。同样jvm不保证对象的finalize一定被调用,但是finalize方法只能被调用一次。

软引用和引用队列

引用队列用于判断软引用是否失效以及释放软引用本身这个引用(强引用)。
当软可及对象被回收之后,虽然这个SoftReference对象的get()方法返回null,但这个SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。如果在创建SoftReference对象的时候,使用了一个ReferenceQueue对象作为参数提供给SoftReference的构造方法,那么软引用被gc处理后,会将软引用本身这个引用加入到referenceQueue中,通过队列的poll方法可以查到对应对象被释放掉的软引用。

构造软引用时引入引用队列:

ReferenceQueue queue = new ReferenceQueue();
SoftReference ref=new SoftReference(aMyObject, queue);

通过引用队列去看是否有被释放的引用对象,此引用已经无效。

SoftReference ref = null;
while ((ref = q.poll()) != null) {
// 清除ref
}

WeakHashMap

一种hashmap,如果key不被引用,则此键值对被移除。

import java.util.Map;
    import java.util.WeakHashMap;

    public class WeakHashMapDemo
    {

        private static Map<String, String> map;

        public static void main(String args[])
        {
            map = new WeakHashMap<String, String>();

            map.put(new String("Maine"), "Augusta");

            Runnable runner = new Runnable()
            {
                public void run()
                {
                    while (map.containsKey("Maine"))
                    {
                        try
                        {
                            Thread.sleep(500);
                        } catch (InterruptedException ignored)
                        {
                        }
                        System.out.println("Thread waiting");
                        System.gc();
                    }
                }
            };
            Thread t = new Thread(runner);
            t.start();
            System.out.println("Main waiting");
            try
            {
                t.join();
            } catch (InterruptedException ignored)
            {
            }
        }
    }
/**
 * output
 * Main waiting
 * Thread waiting
 */

map.put(new String(“Maine”), “Augusta”);
使用匿名参数,对于作为key的string没有强引用指向它,根据weakhashmap的规则,gc的时候这个key对应的键值对被移除。
weakhashmap充分利用了weakreference的特性,使用弱引用来做键值。
关于weakhashmap的一段介绍

WeakHashMap is an implementation of the Map interface that stores only weak references to its keys. Storing only weak references allows a key-value pair to be garbage-collected when its key is no longer referenced outside of the WeakHashMap.

关于weakReference的一段介绍

Weak Reference − If the only references to an object are weak references, the garbage collector can reclaim the object’s memory at any time.it doesn’t have to wait until the system runs out of memory. Usually, it will be freed the next time the garbage collector runs.

参考文档

  1. 软引用和引用队列
    http://alinazh.blog.51cto.com/5459270/1276173