1.前景提示
- 要搞明白强、软、弱、虚这四种引用之前需要对JVM GC垃圾回收知识有所了解
- 可见:【JVM】JVM内存结构+JVM参数配置+GC垃圾回收+OOM内存溢出
2.整体介绍
- 打开JDK文档
- 可以看到Reference下面有三个子类:SoftReference软引用,WeakReference弱引用,PhantomReference虚引用
- 也可以用idea打开类图来看他们之间的关系:
3.详细介绍
3.1 强引用
- 强引用就是我们平常创建对象实例的方式,比如:Object obj = new Objict(); obj就是强引用
- 其实所谓强软弱虚,都是相对于JVM垃圾回收来说的
- 强引用在面对JVM垃圾回收时,具体如下:
- 下面我们写个Demo:
- 这个Demo很简单,创建一个对象,让obj1指向它,然后再把obj1对obj2进行引用赋值。
- 最后把obj1置空,开启GC垃圾回收,打印obj2
- 运行结果:
- obj2还是好好的指向对象实例,这个Demo其实没什么值得说的,把它贴出来也只是跟后面的其他引用做对比
3.2 软引用
- 软引用是一种相对于强引用弱化了一些的引用,需要用java.lang.ref.SoftRefrtence来实现。
- 对于只有软引用的对象来说:
1,当系统内存充足时它不会被回收。
2,当系统内存不足时它会被回收。
- Demo:
/**
* 软引用Demo
* 1.软引用在内存够用时不回收,不够用的时候回收
* 2.demo正常时候运行
* 3.在配置-Xms5m -Xmx5m -XX:+PrintGCDetails下运行
*
* @author wangjie
* @version V1.0
* @date 2020/1/4
*/
public class SoftReferencrDemo {
public static void main(String[] args) {
Object obj1 = new Object();
SoftReference<Object> softReference = new SoftReference<>(obj1);
System.out.println(obj1);
System.out.println(softReference.get());
obj1 = null;
System.gc();
try {
byte[] b = new byte[10 * 1024 * 1024];
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println(obj1);
System.out.println(softReference.get());
}
}
}
- 内存充足时运行结果:
- 在配置-Xms5m -Xmx5m -XX:+PrintGCDetails下,内存不足时运行结果:
- 软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不高用就回收!
3.3 弱引用
- 弱引用需要用java.lang.ref.WeakReference来实现,它比软引用的生存期更短。
- 对于只有弱引用的对象来说,只要垃圾回收一运行,不管JVM的内存是否足够,都会回收该对象。
- Demo:
/**
* 弱引用
*
* @author wangjie
* @version V1.0
* @date 2020/1/4
*/
public class WeakReferenceDemo {
public static void main(String[] args) {
Object obj = new Object();
WeakReference<Object> weakReference = new WeakReference<>(obj);
System.out.println(obj);
System.out.println(weakReference.get());
obj = null;
System.gc();
System.out.println(obj);
System.out.println(weakReference.get());
}
}
- 运行结果:
-弱引用的使用场景:
3.3.1 WeakHashMap
-WeakHashMap是一种弱引用map,内部的key会存储为弱引用,当jvm gc的时候,如果这些key没有强引用存在的话,会被gc回收掉
-Demo:
/**
* todo
*
* @author wangjie
* @version V1.0
* @date 2020/1/4
*/
public class WeakHashMapDemo {
public static void main(String[] args) {
myHashMap();
System.out.println("========================");
myWeakHashMap();
}
private static void myHashMap(){
HashMap<Integer,String> weakHashMap = new HashMap<>();
Integer key = new Integer(1);
String value = "test";
weakHashMap.put(key,value);
System.out.println(weakHashMap);
key = null;
System.out.println(weakHashMap);
System.gc();
System.out.println(weakHashMap+"\t"+weakHashMap.size());
}
private static void myWeakHashMap(){
WeakHashMap<Integer,String> weakHashMap = new WeakHashMap<>();
Integer key = new Integer(1);
String value = "test";
weakHashMap.put(key,value);
System.out.println(weakHashMap);
key = null;
System.out.println(weakHashMap);
System.gc();
System.out.println(weakHashMap+"\t"+weakHashMap.size());
}
}
- 运行结果:
- WeakHashmap业务场景就是缓存,可以有效的节省内存,缓存丢失也不会出太大问题,可以再次获取。许多开源框架,例如tomcat等都使用了weakHashmap做为缓存处理。
3.4 虚引用
- 虚引用需要java.lang.ref.PhantomReference来实现,至于它到底是个什么东西:
- 至于引用队列ReferenceQueue:
- Demo:
/**
* 虚引用
*
* @author wangjie
* @version V1.0
* @date 2020/1/4
*/
public class PhantomReferenceDemo {
public static void main(String[] args) throws InterruptedException {
Object obj = new Object();
ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference<>(obj,referenceQueue);
System.out.println(obj);
System.out.println(phantomReference.get());
System.out.println(referenceQueue.poll());
System.out.println("=====================");
obj = null;
System.gc();
Thread.sleep(500);
System.out.println(obj);
System.out.println(phantomReference.get());
System.out.println(referenceQueue.poll());
}
}
- 运行结果:
- 可以看到虚引用phantomReference.get()无论在垃圾回收前还是回收后都null;
- 反而是引用队列,在gc垃圾回收后把虚引用的对象保存了下来。
- 总结:
【完】
注:文章内所有测试用例源码:https://gitee.com/wjie2018/test-case.git