一:什么是引用
比如A a = new A();a 就是引用的变量名,它指向一个A对象(引用的值),也就是说,当变量指向一个对象时,这个变量就称为引用变量。引用关系在被创建时,首先要在栈内存(stack)上给引用变量a分配一块内存,而被引用的对象A()存储在堆内存(heap)上,然后由栈上面的引用指向堆中对象的地址。
为什么要定义引用:
-
内存使用:定义别名与对象之间的映射关系,以便内存调用,分配
-
内存回收:GC回收内存空间时,依据是判断对象的引用与被引用关系
为什么要对引用分类:
-
可以让程序员通过代码的方式决定某些对象的生命周期
-
有利于GC回收内存空间优化
由此定义了四种引用级别,由高到低依次为:强引用、软引用、弱引用和虚引用
二:实例分析
1)强引用
平时用的最多的引用,类似于 Object obj = new Object(),这种引用的特点是其指向的对象无论如何都不会被 JVM 的垃圾回收器回收;即使是面临着发生内存溢出的风险,只要引用存在,就不会被回收。
public static void main(String[] args) {
String name = new String("James");
System.out.println("word:" + name);
name = new String("Daivd");
System.out.println("word:" + name);
}
代码分析:
创建引用name,并指向 James 对象(第2行),然后引用name指向David 对象(第4行),此时,James 对象无外部引用,会在下一次GC中被回收。
2)软引用
如果有一个对象具有软引用。在内存空间足够的情况下,和强引用的生命周期一样,除非内存空间接近临界值,jvm即将抛出oom的时候,垃圾回收器才会将该引用对象进行回收,最大努力避免系统内存溢出的情况。
public class SoftReferenceDemo {
public static SoftReference<String> softReference;
public static void main(String[] args) {
String name = new String("James");
softReference = new SoftReference<>(name);
System.out.println("word:" + softReference.get());
name = new String("Daivd");
System.out.println("word:" + softReference.get());
System.gc();
System.out.println("word:" + softReference.get());
ArrayList<String> array = new ArrayList<>();
for(int i=0; i<100000000; i++ ) {
array.add(String.valueOf(i));
}
System.gc();
System.out.println("word:" + softReference.get());
}
}
代码分析:
创建name的强应用,同时指向对象 James(第4行),然后创建softReference的软引用也指向 James(第5行),再次更改name强引用,指向David(第7行),此时,James对象只有softReference软引用存在,由于内存资源不紧张,所以输出值是 James (第10行), 然后模拟内存吃紧情况(第11-14行),此时,经过GC后,softReference的get结果值为null(第16行),也就是说,James 对象被回收了。
3)弱引用
当垃圾回收器扫描到弱引用的对象的时候,不管内存空间是否足够,都会直接被垃圾回收器回收。
public class WeakReferenceDemo {
public static WeakReference<String> weakReference;
public static void main(String[] args) {
String name = new String("James");
weakReference = new WeakReference<>(name);
System.out.println("word:" + weakReference.get());
name = new String("Daivd");
System.out.println("word:" + weakReference.get());
System.gc();
System.out.println("word:" + weakReference.get());
}
}
代码分析:
创建name的强应用,同时指向对象 James(第4行),然后创建weakReference的弱引用也指向 James(第5行),再次更改name强引用,指向David(第7行),此时,James对象只有weakReference软引用存在,然后经过GC后,weakReference的get结果值为null(第10行),也就是说,James 对象被回收了。
4)虚引用
虚引用通过PhantomReference类来实现。无法通过虚引用访问对象的任何属性或函数。仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中
三:总结
回顾概述本文传达的知识点
引用类型 | GC回收触发点 | 生命周期 | 场景应用 |
强引用 | 不回收 | JVM停止运行后终止 | 正常应用 |
软引用 | 内存不足 | 内存不足时终止 | 从远程获取到的资源文件,通过软应用缓存下来,用来实现类缓存机制 |
弱引用 | GC周期内 | GC运行后终止 | 使用弱引用避免内存泄露 |
虚引用 | 未知 | 未知 | 跟踪对象被垃圾回收器回收的活动,当一个虚引用关联的对象被垃圾收集器回收之前会收到一条系统通知 |
更多信息请关注 微信公众号 : 白白家族
或扫描白白家族公众号二维码: