类的定义和位置:
package java.lang.ref
public class WeakReference<T> extends Reference<T> {
}
复制代码
作用:
jdk 官网解释:
弱引用主要实现不阻止它的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 里面的实现使用到弱引用