这篇文章非常棒:http://alinazh.blog.51cto.com/5459270/1276173
Java中四种引用:强、软、弱、虚引用
1.1、强引用
当我们使用new 这个关键字创建对象时,被创建的对象就是强引用,如Object object = new Object() 这个Object()就是一个强引用。如果一个对象具有强引用,垃圾回收器就不会去回收有强引用的对象,如当jvm内存不足时,具备强引用的对象,虚拟机宁可会报内存空间不足的异常来终止程序,也不会靠垃圾回收器去回收该对象来解决内存。
1.2、软引用
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;
如果内存空间不足了,就会回收这些对象的内存。
只要垃圾回收器没有回收它,该对象就可以被程序使用。
软引用可用来实现内存敏感的高速缓存(下文给出示例)。
软引用可以和一个引用队列(ReferenceQueue)关联使用:
String str = new String("test"); ReferenceQueue<String> rq = new ReferenceQueue<>(); SoftReference sf = new SoftReference(str,rq);
如果软引用(sf)所引用的对象(str)被垃圾回收器回收,Java虚拟机就会把这个软引用(sf)加入到与之关联的引用队列(rq)中,之后可以通过循环调用rq的poll()方法,来清除无用的软引用对象(sf)
如果软引用所引用的对象(str)还没有被垃圾回收器回收,则可以通过这个引用(sf)的get()方法重新获得对引用对象(str)的强引用.
1.3、弱引用
如果一个对象只具有弱引用,只要垃圾回收器在自己的内存空间中线程检测到了,就会立即被回收,对应内存也会被释放掉。相比软引用弱引用的生命周期要比软引用短很多。不过,如果垃圾回收器是一个优先级很低的线程,也不一定会很快就会释放掉软引用的内存。
通俗的来说就是:发生GC时必定回收弱引用指向的内存空间。
示例代码:
public static void main(String[] args) { String string = new String("test"); ReferenceQueue<String> rq = new ReferenceQueue<>(); WeakReference<String> wr = new WeakReference<String>(string,rq); System.out.println(wr.get()); string = null; System.gc(); System.out.println(wr.get()); }
运行结果:
test null
1.4、虚引用
又称为幽灵引用或幻影引用,虚引用既不会影响对象的生命周期,也无法通过虚引用来获取对象实例,仅用于在发生GC时接收一个系统通知。
相关问题一、若一个对象的引用类型有多个,那到底如何判断它的可达性呢?其实规则如下:
1. 单条引用链的可达性以最弱的一个引用类型来决定;
2. 多条引用链的可达性以最强的一个引用类型来决定;
我们假设图2中引用①和③为强引用,⑤为软引用,⑦为弱引用,对于对象5按照这两个判断原则,路径①-⑤取最弱的引用⑤,因此该路径对对象5的引用为软引用。同样,③-⑦为弱引用。在这两条路径之间取最强的引用,于是对象5是一个软可及对象(当将要发生OOM时则会被回收掉)。
相关问题二、与引用相关联的引用队列的作用是什么
ReferenceQueue queue = new ReferenceQueue(); SoftReference ref=new SoftReference(aMyObject, queue);
SoftReference ref = null; while ((ref = (EmployeeRef) q.poll()) != null) { // 清除ref }
EmployeeCache 类:
import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.Hashtable; public class EmployeeCache { static private EmployeeCache cache; private Hashtable<String, EmployeeRef> employeeRefs; private ReferenceQueue<Employee> q; private class EmployeeRef extends SoftReference<Employee>{ private String _key=""; public EmployeeRef(Employee em,ReferenceQueue<Employee> q) { super(em,q); _key=em.getId(); } } private EmployeeCache() { employeeRefs = new Hashtable<>(); q = new ReferenceQueue<>(); } public static EmployeeCache getInstance(){ if(cache==null){ cache = new EmployeeCache(); } return cache; } private void cacheEmployee(Employee em){ cleanCache(); EmployeeRef ref = new EmployeeRef(em, q); employeeRefs.put(em.getId(), ref); } public Employee getEmployee(String id){ Employee employee = null; if(employeeRefs.contains(id)){ EmployeeRef ref = employeeRefs.get(id); employee = ref.get(); } if(employee == null){ employee = new Employee(id); System.out.println("从信息中心获取新的对象"); this.cacheEmployee(employee); } return employee; } private void cleanCache() { EmployeeRef ref = null; while((ref=(EmployeeRef) q.poll())!=null){ employeeRefs.remove(ref._key); } } public void clearCache(){ cleanCache(); employeeRefs.clear(); System.gc(); System.runFinalization(); } }
Employee类:
import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; public class Employee { private String id; private String name; private String department; private String phone; private int salary; private String origin; public Employee(String id) { this.id = id; getDataFromInfoCenter(); } private void getDataFromInfoCenter() { } public String getId() { String id = (int) (Math.random() * 10 + 1) + ""; return id; } }
2、jdk中的引用实现类
代表软引用的类:java.lang.ref.SoftReference
代表弱引用的类:java.lang.ref.WeakReference
代表虚引用的类:java.lang.ref.PhantomReference
他们同时继承了:java.lang.ref.Reference
引用队列:java.lang.ref.ReferenceQueue,这个引用队列是可以三种引用类型联合使用的,以便跟踪java虚拟机回收所引用对象的活动。
附:相关源码
1 /* 2 * @(#)ReferenceQueue.java 1.23 03/12/19 3 * 4 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 5 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 6 */ 7 8 package java.lang.ref; 9 10 /** 11 * Reference queues, to which registered reference objects are appended by the 12 * garbage collector after the appropriate reachability changes are detected. 13 * 14 * @version 1.23, 12/19/03 15 * @author Mark Reinhold 16 * @since 1.2 17 */ 18 19 public class ReferenceQueue<T> { 20 21 /** 22 * Constructs a new reference-object queue. 23 */ 24 public ReferenceQueue() { } 25 26 private static class Null extends ReferenceQueue { 27 boolean enqueue(Reference r) { 28 return false; 29 } 30 } 31 32 static ReferenceQueue NULL = new Null(); 33 static ReferenceQueue ENQUEUED = new Null(); 34 35 static private class Lock { }; 36 private Lock lock = new Lock(); 37 private Reference<? extends T> head = null; 38 private long queueLength = 0; 39 40 boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */ 41 synchronized (r) { 42 if (r.queue == ENQUEUED) return false; 43 synchronized (lock) { 44 r.queue = ENQUEUED; 45 r.next = (head == null) ? r : head; 46 head = r; 47 queueLength++; 48 if (r instanceof FinalReference) { 49 sun.misc.VM.addFinalRefCount(1); 50 } 51 lock.notifyAll(); 52 return true; 53 } 54 } 55 } 56 57 private Reference<? extends T> reallyPoll() { /* Must hold lock */ 58 if (head != null) { 59 Reference<? extends T> r = head; 60 head = (r.next == r) ? null : r.next; 61 r.queue = NULL; 62 r.next = r; 63 queueLength--; 64 if (r instanceof FinalReference) { 65 sun.misc.VM.addFinalRefCount(-1); 66 } 67 return r; 68 } 69 return null; 70 } 71 72 /** 73 * Polls this queue to see if a reference object is available. If one is 74 * available without further delay then it is removed from the queue and 75 * returned. Otherwise this method immediately returns <tt>null</tt>. 76 * 77 * @return A reference object, if one was immediately available, 78 * otherwise <code>null</code> 79 */ 80 public Reference<? extends T> poll() { 81 synchronized (lock) { 82 return reallyPoll(); 83 } 84 } 85 86 /** 87 * Removes the next reference object in this queue, blocking until either 88 * one becomes available or the given timeout period expires. 89 * 90 * <p> This method does not offer real-time guarantees: It schedules the 91 * timeout as if by invoking the {@link Object#wait(long)} method. 92 * 93 * @param timeout If positive, block for up <code>timeout</code> 94 * milliseconds while waiting for a reference to be 95 * added to this queue. If zero, block indefinitely. 96 * 97 * @return A reference object, if one was available within the specified 98 * timeout period, otherwise <code>null</code> 99 * 100 * @throws IllegalArgumentException 101 * If the value of the timeout argument is negative 102 * 103 * @throws InterruptedException 104 * If the timeout wait is interrupted 105 */ 106 public Reference<? extends T> remove(long timeout) 107 throws IllegalArgumentException, InterruptedException 108 { 109 if (timeout < 0) { 110 throw new IllegalArgumentException("Negative timeout value"); 111 } 112 synchronized (lock) { 113 Reference<? extends T> r = reallyPoll(); 114 if (r != null) return r; 115 for (;;) { 116 lock.wait(timeout); 117 r = reallyPoll(); 118 if (r != null) return r; 119 if (timeout != 0) return null; 120 } 121 } 122 } 123 124 /** 125 * Removes the next reference object in this queue, blocking until one 126 * becomes available. 127 * 128 * @return A reference object, blocking until one becomes available 129 * @throws InterruptedException If the wait is interrupted 130 */ 131 public Reference<? extends T> remove() throws InterruptedException { 132 return remove(0); 133 } 134 135 }
1 /* 2 * @(#)SoftReference.java 1.34 03/12/19 3 * 4 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 5 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 6 */ 7 8 package java.lang.ref; 9 10 11 /** 12 * Soft reference objects, which are cleared at the discretion of the garbage 13 * collector in response to memory demand. Soft references are most often used 14 * to implement memory-sensitive caches. 15 * 16 * <p> Suppose that the garbage collector determines at a certain point in time 17 * that an object is <a href="package-summary.html#reachability">softly 18 * reachable</a>. At that time it may choose to clear atomically all soft 19 * references to that object and all soft references to any other 20 * softly-reachable objects from which that object is reachable through a chain 21 * of strong references. At the same time or at some later time it will 22 * enqueue those newly-cleared soft references that are registered with 23 * reference queues. 24 * 25 * <p> All soft references to softly-reachable objects are guaranteed to have 26 * been cleared before the virtual machine throws an 27 * <code>OutOfMemoryError</code>. Otherwise no constraints are placed upon the 28 * time at which a soft reference will be cleared or the order in which a set 29 * of such references to different objects will be cleared. Virtual machine 30 * implementations are, however, encouraged to bias against clearing 31 * recently-created or recently-used soft references. 32 * 33 * <p> Direct instances of this class may be used to implement simple caches; 34 * this class or derived subclasses may also be used in larger data structures 35 * to implement more sophisticated caches. As long as the referent of a soft 36 * reference is strongly reachable, that is, is actually in use, the soft 37 * reference will not be cleared. Thus a sophisticated cache can, for example, 38 * prevent its most recently used entries from being discarded by keeping 39 * strong referents to those entries, leaving the remaining entries to be 40 * discarded at the discretion of the garbage collector. 41 * 42 * @version 1.34, 12/19/03 43 * @author Mark Reinhold 44 * @since 1.2 45 */ 46 47 public class SoftReference<T> extends Reference<T> { 48 49 /* Timestamp clock, updated by the garbage collector 50 */ 51 static private long clock; 52 53 /* Timestamp updated by each invocation of the get method. The VM may use 54 * this field when selecting soft references to be cleared, but it is not 55 * required to do so. 56 */ 57 private long timestamp; 58 59 /** 60 * Creates a new soft reference that refers to the given object. The new 61 * reference is not registered with any queue. 62 * 63 * @param referent object the new soft reference will refer to 64 */ 65 public SoftReference(T referent) { 66 super(referent); 67 this.timestamp = clock; 68 } 69 70 /** 71 * Creates a new soft reference that refers to the given object and is 72 * registered with the given queue. 73 * 74 * @param referent object the new soft reference will refer to 75 * @param q the queue with which the reference is to be registered, 76 * or <tt>null</tt> if registration is not required 77 * 78 */ 79 public SoftReference(T referent, ReferenceQueue<? super T> q) { 80 super(referent, q); 81 this.timestamp = clock; 82 } 83 84 /** 85 * Returns this reference object's referent. If this reference object has 86 * been cleared, either by the program or by the garbage collector, then 87 * this method returns <code>null</code>. 88 * 89 * @return The object to which this reference refers, or 90 * <code>null</code> if this reference object has been cleared 91 */ 92 public T get() { 93 T o = super.get(); 94 if (o != null) this.timestamp = clock; 95 return o; 96 } 97 98 }