JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用,软引用,弱引用,虚引用4种,这四种引用强度依次逐渐减弱,除了强引用外,其他三种引用类型都在java,lang包下,可直接使用
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/d9623a4ed09a3ec224605161ef5f1fd9.png)
简单介绍下四种引用:
- 强引用:类似
Object obj = new Object();
这种引用关系就叫做强引用,无论在任何情况下,只要强引用关系还在,垃圾收集器就永远不会回收掉被引用的对象 - 软引用:在系统发生内存溢出之前,将会把这些对象列入回收范围中进行第二次回收,如果这次回收后还没有足够的内存,才会抛出内存溢出异常,即内存不足即回收
- 弱引用:只要垃圾收集器工作,无论空间是否足够,都会回收掉被弱引用关联的对象
- 虚引用:一个对象是否有虚引用的存在不影响其生命周期,也无法通过虚引用来获得一个对象的实例,未一个对象设置虚引用的唯一目的就是能在这个对象被垃圾收集器回收时收到一个系统通知
1.强引用
在java程序中,99%都是强引用,也是默认的引用类型,只要强引用关系还在,垃圾收集器就永远不会回收掉被引用的对象,强引用是造成内存泄漏的主要原因之一,强引用可直接访问目标对象,强引用所指的对象在任何时候都不会被系统回收,即使系统抛出OOM异常
2.软引用
弱引用用来描述一些还有用,但非必须的对象,在第一次垃圾回收(对象不可达)之后,系统发生内存溢出之前,将会把这些对象列入回收范围中进行第二次回收,如果这次回收后还没有足够的内存,才会抛出内存溢出异常,这里要注意一点,软引用不会导致内存溢出异常
软引用通常用来实现内存敏感的缓存,比如高速缓存,如果还有空闲内存就可以展示保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存,Mybatis里的内部类就使用了内部类
总结的话就是:
内存足够 | 不回收软引用的可达对象 |
---|---|
内存不足 | 回收软引用的可达对象 |
举例:
public static void main(String[] args) {
//SoftReference<user> soft1 = new SoftReference<>(new user(1,"rwh"));这行代码等同于下面三行代码
user u1 = new user(1,"rwh");
SoftReference<user> soft = new SoftReference<>(u1);
u1 = null;
//获取弱引用中的对象
System.out.println("before gc");
System.out.println(soft.get());
System.gc();
System.out.println("after gc");
System.out.println(soft.get());//内存足够,不会回收对象
try {
//-Xms10m -Xmx10m设置堆内存大小,并且创建大对象,使系统内存不足
byte[] b = new byte[1024 * 1024 * 7];
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println(soft.get());//在OOM之前系统会回收软引用的可达对象
}
}
3.弱引用
JDK1.2之后提供了java.lang.WeakReference
来实现弱引用,弱引用和软引用都非常适合用来保存可有可无的缓存数据
4.虚引用
是所有引用中最弱的一个,一个对象是否有虚引用的存在,完全不会决定对象的生命周期,如果一个对象仅持有虚引用,那么它和没有引用几乎是一样的,随时都可能被垃圾回收器回收,JDK1.2之后提供了java.lang.ReferenceQueue
来实现虚引用:
Object obj = new Object();
ReferenceQueue<Object> ref = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference<>(obj,ref);
虚引用必须和引用队列一起使用,虚引用在创建时必须提供一个引用队列作为参数,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象后,将这个虚引用加入引用队列,以通知对象的回收情况,由于虚引用可跟踪对象的回收时间,可以将一些释放资源操作放在虚引用中执行和记录