原贴地址:http://www.appcnd.com/blog/articles/90.html
在Java中,除了原始数据类型的变量,其他所有都属于引用类型、指向各种不同的对象。
引用包含4种不同的类型:强引用、软引用、弱引用、幻象引用;不同的引用类型,主要体现的是对象不同的可达性状态和对垃圾回收的影响。
强引用
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
软引用
软引用是用来描述一些有用但并不是必需的对象,在Java中用java.lang.ref.SoftReference类来表示。对于软引用关联着的对象,只有在内存不足的时候JVM才会回收该对象。因此,这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。
弱引用
弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。
幻象引用
和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与幻象引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。幻象引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有幻象引用,就会把这个幻象引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了幻象引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个幻象引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
验证
设置堆大小(新生代≈10M,老年代≈10M)
| 1 | -Xms20m -Xmx20m -XX:NewRatio=1 |
MyObj:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class MyObj { public MyObj() { System.out.println("对象" + this + "创建"); } /** * 重写finalize方法,在对象被gc的时候打印日志 * @throws Throwable */ @Override protected void finalize() throws Throwable { super.finalize(); System.out.println(this + " is gc"); } } |
1、强引用
1.1
| 1 2 3 4 5 6 | @Test public void test01() { MyObj obj = new MyObj(); // new一个20M的byte数组,使堆空间不足,进而触发gc byte[] bytes = new byte[1024 * 1024 * 20]; } |
| 1 2 | 对象com.test.MyObj@4e9ba398创建 java.lang.OutOfMemoryError: Java heap space |
分析:对于强引用对象,即使堆空间不足的时候也不会被垃圾回收。
1.2
| 1 2 3 4 5 6 7 | @Test public void test01() { MyObj obj = new MyObj(); obj = null; // new一个20M的byte数组,使堆空间不足,进而触发gc byte[] bytes = new byte[1024 * 1024 * 20]; } |
| 1 2 3 | 对象com.test.MyObj@4e9ba398创建 com.test.MyObj@4e9ba398 is gc java.lang.OutOfMemoryError: Java heap space |
分析:将强引用置为null后,gc的时候才会被回收。
2、软引用
2.1
| 1 2 3 4 5 6 7 8 | @Test public void test01() { SoftReference<MyObj> softReference = new SoftReference<MyObj>(new MyObj()); System.out.println("堆空间充足的时候主动触发gc"); System.gc(); System.out.println("new一个20M的byte数组,使堆空间不足,进而触发gc"); byte[] bytes = new byte[1024 * 1024 * 20]; } |
| 1 2 3 4 5 | 对象com.test.MyObj@4e9ba398创建 堆空间充足的时候主动触发gc new一个20M的byte数组,使堆空间不足,进而触发gc com.test.MyObj@4e9ba398 is gc java.lang.OutOfMemoryError: Java heap space |
分析:可以明显看到在堆空间充足的时候,jvm不会回收软引用对象,软引用对象只有在堆空间不足的时候才会被回收。
2.2 结合ReferenceQueue使用
| 1 2 3 4 | ReferenceQueue<MyObj> queue = new ReferenceQueue(); MyObj obj = new MyObj(); // 在obj被jvm回收的时候,相应的reference对象(softReference)会被放到queue里 SoftReference<MyObj> softReference = new SoftReference<MyObj>(obj, queue); |
3、弱引用
| 1 2 3 4 5 6 | @Test public void test01() { WeakReference<MyObj> weakReference = new WeakReference<MyObj>(new MyObj()); System.out.println("堆空间充足的时候主动触发gc"); System.gc(); } |
| 1 2 3 | 对象com.test.MyObj@4e9ba398创建 堆空间充足的时候主动触发gc com.test.MyObj@4e9ba398 is gc |
| 1 2 3 4 5 6 | @Test public void test01() { WeakReference<MyObj> weakReference = new WeakReference<MyObj>(new MyObj()); System.out.println("new一个20M的byte数组,使堆空间不足,进而触发gc"); byte[] bytes = new byte[1024 * 1024 * 20]; } |
| 1 2 3 4 | 对象com.test.MyObj@4e9ba398创建 new一个20M的byte数组,使堆空间不足,进而触发gc com.test.MyObj@4e9ba398 is gc java.lang.OutOfMemoryError: Java heap space |
分析:对于弱引用对象,无论堆内存是否充足,只要发生gc,弱引用对象都会被回收。
弱引用也可以结合ReferenceQueue来使用,在弱引用对象被回收的时候,其对应的reference对象会被放入queue中。