每种编程语言都有本身操做内存中元素的方式,例如在 C 和 C++ 里是经过指针,而在 Java 中则是经过“引用”。在 Java 中一切都被视为了对象,可是咱们操做的标识符其实是对象的一个引用(reference)。html
从JDK 1.2版本开始,把对象的引用分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种引用的强度依次减弱:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种。java
//建立一个引用,引用能够独立存在,并不必定须要与一个对象关联 String s; //经过这个引用标识符指向某个对象,以后即可以经过这个引用来实现操做对象了。 s = new String("abc"); System.out.println(str.toString());
Java 中的垃圾回收机制在判断是否回收某个对象的时候,都须要依据“引用”这个概念。
在不一样垃圾回收算法中,对引用的判断方式有所不一样:算法
Java中默认声明的就是强引用,只要强引用存在,垃圾回收器将永远不会回收被引用的对象,哪怕内存不足时,JVM也只会直接抛出OutOfMemoryError,不会去回收。若是想中断强引用与对象之间的联系,能够显示的将强引用赋值为null,这样一来,JVM就能够适时的回收对象了。例如:编程
//只要obj还指向Object对象,Object对象就不会被回收 Object obj = new Object(); //将强引用赋值为null后JVM能够回收 obj = null;
软引用是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,GC则会回收软引用对象,若是回收了软引用对象以后仍然没有足够的内存,才会抛出内存溢出异常。这种特性经常被用来实现缓存技术,好比网页缓存,图片缓存等。在 JDK1.2 以后,用java.lang.ref.SoftReference类来表示软引用。数组
接下来作个测试,个人内存配置以下图:缓存
软引用:编程语言
public static void testSoftReference() { for (int i = 0; i < 5; i++) { //建立弱引用字节数组 byte[] buff = new byte[1024 * 1024 * 1000]; SoftReference<byte[]> sr = new SoftReference<byte[]>(buff); list.add(sr); } //主动通知垃圾回收,内存不足时回收弱引用 System.gc(); for(int i=0; i < list.size(); i++){ Object obj = ((SoftReference) list.get(i)).get(); System.out.println(obj); } }
测试结果:
null null null null [B@14ae5a5
打印结果老是只有最后一个对象被保留,其余的obj全都被置空回收了。这里就说明了在内存不足的状况下,软引用将会被自动回收。即便有 byte[] buff 引用指向对象, 且 buff 是一个strong reference, 可是 SoftReference sr 指向的对象仍然被回收了,这是由于Java的编译器发现了在以后的代码中, buff 已经没有被使用了, 因此自动进行了优化。测试
强引用:优化
public static void testSoftReference1() { //强引用 byte[] buff = null; for (int i = 0; i < 5; i++) { buff = new byte[1024 * 1024 * 1000]; SoftReference<byte[]> sr = new SoftReference<byte[]>(buff); list.add(sr); } //主动通知垃圾回收,内存不足时回收弱引用 System.gc(); for(int i=0; i < list.size(); i++){ Object obj = ((SoftReference) list.get(i)).get(); System.out.println(obj); } }
结果:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at com.demo.ReferenceTest.testSoftReference1(ReferenceTest.java:45) at com.demo.ReferenceTest.main(ReferenceTest.java:20)
buff 会由于强引用的存在,而没法被垃圾回收,从而抛出OOM的错误。this
弱引用的引用强度比软引用要更弱一些,不管内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。在 JDK1.2 以后,用 java.lang.ref.WeakReference 来表示弱引用。
public static void testWeakReference() { for (int i = 0; i < 5; i++) { byte[] buff = new byte[1024 * 1024 * 1000]; WeakReference<byte[]> sr = new WeakReference<byte[]>(buff); list.add(sr); } //主动通知垃圾回收 System.gc(); for(int i=0; i < list.size(); i++){ Object obj = ((WeakReference) list.get(i)).get(); System.out.println(obj); } }
结果:
null null null null null
能够发现全部被弱引用关联的对象都被垃圾回收了。
弱引用与软引用的区别在于:只具备弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程当中,一旦发现了只具备弱引用的对象,无论当前内存空间足够与否,都会回收它的内存。不过,因为垃圾回收器是一个优先级很低的线程,所以不必定会很快发现那些只具备弱引用的对象。
(1)概念
“虚引用”顾名思义,就是形同虚设,与其余几种引用都不一样,虚引用并不会决定对象的生命周期。若是一个对象仅持有虚引用,那么它就和没有任何引用同样,在任什么时候候均可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,若是发现它还有虚引用,就会在回收对象的内存以前,把这个虚引用加入到与之 关联的引用队列中。
public class PhantomReference<T> extends Reference<T> { /** * Returns this reference object's referent. Because the referent of a * phantom reference is always inaccessible, this method always returns * <code>null</code>. * * @return <code>null</code> */ public T get() { return null; } public PhantomReference(T referent, ReferenceQueue<? super T> q) { super(referent, q); } }
(2)引用队列(ReferenceQueue)
引用队列能够与软引用、弱引用以及虚引用一块儿配合使用,当垃圾回收器准备回收一个对象时,若是发现它还有引用,那么就会在回收对象以前,把这个引用加入到与之关联的引用队列中去。程序能够经过判断引用队列中是否已经加入了引用,来判断被引用的对象是否将要被垃圾回收,这样就能够在对象被回收以前采起一些必要的措施。
与软引用、弱引用不一样,虚引用必须和引用队列一块儿使用。