一、强引用
- 特点:我们平常典型编码Object obj = new Object()中的obj就是强引用。通过关键字new创建的对象所关联的引用就是强引用。
当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常终止,也不会靠随意回收具有强引用的“存活”对象来解决内存不足的问题。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,具体回收时机还是要看垃圾收集策略
栗子:
- 下面以HashMap为例,我们看看HashMap键值对中的:
key
是不是强引用
public class Test {
public static void main(String[] args) {
//强引用
String s1 = new String("s1");
String s2 = new String("s2");
HashMap<String,Integer> map = new HashMap<>();
map.put(s1,1);
map.put(s2,1);
s1 = s2 = null;
System.gc();
System.out.println(map);
}
}
- 运行结果:
{s1=1, s2=1}
分析:我们看到上面代码,我们创建了两个强引用:s1,s2;作为HashMap中的key传入,然后我们把s1,s2值为null,调用System.gc();
,但是HashMap还是正常输出了,那么显而易见:HashMap存储的key是强引用
注意:我上述代码其实并不严格,因为调用:System.gc();
并不是说垃圾回收立刻就过来回收我们的:s1,s2;通俗说,我们只是给GC一个信息:老哥,待会过来帮我清理下垃圾;至于什么时候来,那是由JVM来调度分配的,大家知道就好了!
二、软引用
- 特点:当发生GC时候,只有当内存不够用时候,这些软引用的对象才被回收
- 应用:聊天记录,视频缓存
栗子:
- 我们下面以
SoftReference
为例来看软引用
class MyArray{
byte[] array = new byte[1024*1024*3];//3M
}
public class SoftReferenceTest {
public static void main(String[] args) {
//引用队列:存储被GC回收的对象 判断对象是否被回收
ReferenceQueue<MyArray> queue = new ReferenceQueue<>();
//强引用:MyArray a = new MyArray();
//软引用的创建方式
SoftReference<MyArray> s = new SoftReference<>(new MyArray(),queue);
System.out.println(queue.poll());
//这里再开辟3M内存,让我们堆内存全被占用
byte[]bytes = new byte[1024*1024*3];
System.out.println(queue.poll());
}
}
三、弱引用
- 特点:强度比软引用更弱一些,当GC时候,不管内存是否够用都会被回收
栗子:
- 我们以WeakHashMap为例,来验证WeakHashMap中的key为弱引用
public class WeakHashMapTest {
public static void main(String[] args) {
WeakHashMap<String,Integer> map = new WeakHashMap<>();
//强引用
String s1 = new String("s1");
String s2 = new String("s2");
String s3 = new String("s3");
String s4 = new String("s4");
//插入元素
map.put(s1,1);
map.put(s2,1);
map.put(s3,1);
map.put(s4,1);
//遍历
Iterator<Map.Entry<String,Integer>> iterator = map.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry<String,Integer> next = iterator.next();
System.out.println("key: "+next.getKey()+" value: "+next.getValue());
}
//验证WeakHashMap中的key是弱引用
System.out.println("-----------------");
//释放强引用
s1 = s2 = s3 = s4 = null;
System.gc();
System.out.println(map);
}
}
运行结果:
key: s4 value: 1
key: s3 value: 1
key: s1 value: 1
key: s2 value: 1
-----------------
{}
- 分析:同开始的HashMap一样,我们也是创建了几个强引用作为WeakHashMap的key值,当我们把强引用值为null,然后调用GC,我们看到输出结果为:
{}
;也就是被回收了
四、虚引用
- 特点:不会对对象造成任何影响。和引用队列联合是用来判断这个对象是否被回收
栗子
- 我们以PhanReference为栗看看虚引用
class Mrray{
byte[]bytes = new byte[1024*1024*3];
}
public class PhanReferenceTest {
public static void main(String[] args) {
//引用队列:存储被GC回收的对象 判断对象是否被回收
ReferenceQueue<Mrray> queue = new ReferenceQueue<>();
//虚引用
PhantomReference<Mrray> ptr = new PhantomReference<>(new Mrray(),queue);
System.gc();
try {
Thread.sleep(1000);//让GC充分发生 等待一会儿
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(queue.poll());//队列能够获取到这个对象说明这个对象被回收了
}
}
- 虚引用是使用PhantomReference创建的引用,虚引用也称为幽灵引用或者幻影引用,是所有引用类型中最弱的一个。一个对象是否有虚引用的存在,完全不会对其生命周期构成影响,也无法通过虚引用获得一个对象实例