package java.lang.ref public class WeakReference<T> extends Reference<T> { } 复制代码
弱引用主要实现不阻止它的key或者value 被回收的mapping。直接贴英文吧,翻译水平有限(weak references are for implementing canonicalizing mappings that do not prevent their keys (or values) from being reclaimed)
它的作用是引用一个对象,但是并不阻止该对象被回收。如果使用一个强引用的话,只要该引用存在,那么被引用的对象是不能被回收的。弱引用则没有这个问题。在垃圾回收器运行的时候,如果一个对象的所有引用都是弱引用的话,该对象会被回收
在举例弱引用之前我先解释下强引用,对比来方便大家理解:
强引用很好理解就是我们平时new 一个对象。例如:
String str = new String("我是强引用"); 复制代码
垃圾回收器有一个可达性判断,如果使用一个强引用的话,只要该引用存在,那么被引用的对象是不能被回收的; 单单看文字有点难理解,下面举个例子
public class StrongRefenceDemo { static Map<String, String> map; public static void main(String[] args) throws Exception { StrongRefenceDemo demo = new StrongRefenceDemo(); demo.strongTest(); System.out.println("gc 发生前:" + map.get("str")); System.out.println("开始通知GC"); //注意,这里只是通过垃圾回收器进行垃圾回收,并不一定马上执行 System.gc(); Thread.sleep(1000 * 5); System.out.println("gc 发生后:" + map.get("str")); } /** * 强引用测试 */ public void strongTest() { String str = new String("我被强引用引用,但是我还没有被垃圾回收"); map = new HashMap(); map.put("str", str); } } 复制代码
运行后输出结果:
gc 发生前:我被强引用引用,但是我还没有被垃圾回收
开始通知GC
gc 发生后:我被强引用引用,但是我还没有被垃圾回收
复制代码
相信大家对上面的结果没什么疑问,毕竟str 还是被一个强引用map 引用,垃圾回收器是不能回收它的。
但是这里我有一个好奇,假如这里的str 指向的对象在执行完strongTest()方法 以后用不着了,但是我可能又不是很好的判断去主动调用remove 来移除它。想要垃圾回收器自己判断回收掉可不可以呢?答案其实是可以的,这个时候就是弱引用上场了,请看下面程序
public class WeakRefenceDemo { static WeakReference<String> weakReference; public static void main(String[] args) throws Exception { WeakRefenceDemo demo = new WeakRefenceDemo(); demo.weakTest(); System.out.println("gc 发生前:" + weakReference.get()); System.out.println("开始通知GC"); //注意,这里只是通过垃圾回收器进行垃圾回收,并不一定马上执行 System.gc(); Thread.sleep(1000 * 5); System.out.println("gc 发生后:" + weakReference.get()); } /** * 弱引用测试 */ public void weakTest() { String str = new String("我被弱引用引用,但是我还没有被垃圾回收"); weakReference = new WeakReference(str); } } 复制代码
运行上面代码输出结果
gc 发生前:我被弱引用引用,但是我还没有被垃圾回收
开始通知GC
gc 发生后:null
复制代码
运行结果解析:
这里大家看到输出的是null 也就是意味着已经被垃圾回收器回收掉了。也证明可我们上面说的弱引用并不阻止该对象被回收
正常情况下,一个对象应该与它里面包含的对象的生命周期是一致的。打个比方,我有一个全局的map ,那么这个map和它里面的对象的生命周期应该是一致的。假如说一个map 里面的对象的生命周期是比map 对象本身的生命周期要长,在我们没有主动调用map 的remove 方法的时候,垃圾回收器是不会回收掉该对象的。如果这种生命周期相对短的对象很多,最终就有可能消耗掉JVM中全部的内存。 最理想的状态其实就是这些生命周期相对短的对象,在它的生命周期结束之后,即使我们没有手动的调用remove 也可以被垃圾收集器回收掉。对于这种情况的解决办法就是使用弱引用来引用这些对象,这样哈希表中的键和值对象都能被垃圾回收。Java中提供了WeakHashMap来满足这一常见需求。
其实这里还有一个重大的使用场景就是jdk 里面大名鼎鼎的ThreadLocal, 接下来会写一篇文章分析,为什么ThreadLocal 里面的实现使用到弱引用
jdk8官方文档解析弱引用