强引用、软引用、弱引用、虚引用以及ThreadLocal原理

2019-06-29  本文已影响0人  纳米君
一. 强引用、软引用、弱引用和虚引用
String s = new String("hello");
s = null; //不加该行,会输出hello
System.gc(); //垃圾回收
System.out.println(s);

输出结果:null

对象只有在创建它的方法执行结束才会被回收,或者主动设置obj = null。
SoftReference<Object[]> reference = new SoftReference<>(new Object[300000000]);
System.out.println(reference.get());
Object[] objects = new Object[100000000];// 3
System.out.println(reference.get());

输出结果:
[Ljava.lang.Object;@4554617c
null

结果说明执行代码3时,内存不够,垃圾回收器主动回收了软引用指向的对象。
PS:Object数组长度根据JVM配置不同而不同。
WeakReference<String> reference = new WeakReference<>(new String("hello"));
System.out.println(reference.get());
System.gc(); //垃圾回收
System.out.println(reference.get());

输出结果:
hello
null
ReferenceQueue<String> queue = new ReferenceQueue<>();
PhantomReference<String> reference = new PhantomReference<>(new String("hello"), queue);
System.out.println(reference.get());

输出结果:
null
二. ThreadLocal

一个线程可以有多个ThreadLocal实例。其作用是存储线程本地变量,独享资源,避免和主内存通信,从而提高效率。

原理:都是操作线程中的ThreadLocalMap对象。
set(obj): 获取当前线程中的ThreadLocalMap,以ThreadLocal实例为keyobjvalue,并且key是弱引用。也就是说ThreadLocal实例(未被其他变量强引用)被垃圾回收器扫描到就会被回收,从而导致key = null。这就是为什么get、set、remove的时候都会有清除Entry[]key = null的数据的步骤。

remove():会把当前key、value、key-value所在位置Entry[i]置为null,以及清除Entry[]中从i到末尾上key = null的数据。

内存泄露:key是弱引用,所以垃圾回收器会主动回收。但是valueEntry[i]都是强引用,只有线程销毁的时候才会被回收。当线程长时间未被销毁,或者线程池循环利用线程的时候,valueEntry[i]一直被强引用,不会被垃圾回收器回收,可能会造成OOM。

解决方法:使用完务必调用remove()方法,防止内存泄漏。


以上。

上一篇 下一篇

猜你喜欢

热点阅读