背景
最近在研究ThreadLocal中发现最终存储的ThreadLocalMap中的key为弱引用,因此来分析下使用弱引用的原因
实验
引用链为
//list =>> person1
因此在GC的时候 list还强引用三个对象,导致三个person不会被gc释放掉
@Test
public void test2() {
Person person1 = new Person();
List<Person> list = new ArrayList<>();
list.add(person1);
person1=null;
System.gc();
System.out.println(list);
}
使用弱引用
弱引用当GC时候如果不存在强引用那么就被释放
以下代码调用链路为
list ===>> WeakReference ===>> person1
结果:
最终效果 person1被释放掉了
jvm在GCRoot查询的时候查询到WeakReference
则就不会在向下扫描里面的Referent
所以导致Referent
无引用就被释放调了
注意 new Person()实在堆中的 只剩 WeakReference
在引用才会被GC释放,如果还包含强引用,则以强引用为主
@Test
public void test() {
Person person1 = new Person();
List<WeakReference<Person>> list = new ArrayList<>();
list.add(new WeakReference<>(person1));
person1=null;
System.gc();
System.out.println(list);
}
总结
个人理解
每种引用中都包含Reference栈指针
引用 | 描述 | 使用场景 |
---|
强引用 | 直接new出来的对象,只有在没有被引用才会释放 | 常规的new对象 |
软引用 | 通过SoftReference 创建出来的对象里面包含Reference指向的堆,只有内存在不足GC时候释放Reference指向的的堆内存原有对象 | 一般用来做缓存 |
弱引用 | 通过WeakReference 创建出来的对象里面包含Reference指向的堆,在GC释放会释放Reference指向的的堆内存 | 有ThreadLocal中map的key为弱引用来方式内存泄露(不过个人感觉意义不大,必经大部分使用ThreadLocal的场景都是静态的) |
虚引用 | 通过PhantomReference 创建,必须和引用队列一起使用(ReferenceQueue ),如果一个对象仅有虚引用那么他可以在任何地方释放,并把释放的对象加到队列中 | 一般使用它的继承类Cleaner 来做对象释放后的清理工作如NIO中的堆外内存采用的就是虚引用来释放内存 |
参考文章:
- 引用介绍
- ThreadLocal源码解析
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)