欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

强引用、软引用、弱引用、幻象引用有什么区别?具体使用场景是什么?

程序员文章站 2022-07-04 11:35:34
...

 

  Java 语言中,除了原始数据类型的变量,其他所有都是所谓的引用类型,指向各种不同的对象。理解引用对于掌握 Java 对象生命周期和 JVM 内部相关机制非常有帮助。不同的引用类型,主要体现的是对象不同的可达性(reachable)状态和对垃圾收集的影响。

 

引用出现的根源是由于GC内存回收的基本原理-GC回收内本质上是回收对象,而目前比较流行的回收算法是可达性分析算法,从GC Roots开始按照一定的逻辑判断一个对象是否可达,不可达的话就说明该对象已死(除此之外另外一种常见的算法就是引用计数法,但是这种算法不能解决相互引用的问题)。基于此Java向用户提供了四种可用的引用:强引用、软引用、弱引用和幻象引用,同时还提供了一种不可被使用的引用-FinalReference,这个引用是和析构函数密切相关的。

 

强引用是开发者通过new的方式创建的,其他几种引用Java提供了相应的类:SoftReferenceWeakReferencePlantomReference。如果你去查看源码,你会发现这个类实现的核心是ReferenceReferenceQueue(引用队列)两个类,而且这两个类也特别的简单。

Java世界泰山北斗级大作《Thinking In Java》切入Java就提出“Everything is Object”。在Java这个充满Object的世界中,Reference是一切谜题的根源,所有的故事都是从这里开始的。

 

Reference类似一个链表结构,通过创建一个守护线程来执行对应引用的清除、Cleaner.clean、以及引用的入队操作。

ReferenceQueue是指定了引用队列的一些具体操作,简单来说它是一个链表结构,并提供了一些基本的链表操作。而除了强引用外其他的都是继承于此,通过这样的类约束了引用的相关内容,便于和GC进行交互。

 

这几类引用的区别如下:

1、强引用是通过new创建的对象引用。只有当GC明确判断该引用无效时才会回收相应的引用对象,即使抛出OOM

 

2、软引用是当GC检测到继续创建对象会导致OOM时会进行一次垃圾回收,这次回收会将软引用回收以防抛出异常,根据这样的特点该引用常用来被当做缓存使用。图片缓存框架中,“内存缓存”中的图片是以这种引用来保存,使得JVM在发生OOM之前,可以回收这部分缓存。在静态内部类中,经常会使用虚引用。例如,一个类发送网络请求,承担callback的静态内部类,则常以虚引用的方式来保存外部类(宿主类)的引用,当外部类需要被JVM回收时,不会因为网络请求没有及时回来,导致外部类不能被回收,引起内存泄漏。

 

3、虚引用是那些如果引用未被使用,就会在最近的一次GC时被回收。例如JavaThreadLocal与动态代理都是基于这样的一个引用实现的,一般针对那些比较敏感的数据。

 

4、幻象引用是针对那些已经执行完析构函数之后,仍然需要再执行一些其他操作的对象,比如资源对象的关闭就可以用到该引用。

 

除了幻象引用(因为 get 永远返回 null),如果对象还没有被销毁,都可以通过 get 方法获取原有对象。这意味着,利用软引用和弱引用,我们可以将访问到的对象,重新指向强引用,也就是人为的改变了对象的可达性状态!所以,对于软引用、弱引用之类,垃圾收集器可能会存在二次确认的问题,以保证处于弱引用状态的对象,没有改变为强引用。

 

如果我们错误的保持了强引用(比如,赋值给了 static 变量),那么对象可能就没有机会变回类似弱引用的可达性状态了,就会产生内存泄漏。所以,检查弱引用指向对象是否被垃圾收集,也是诊断是否有特定内存泄漏的一个思路,如果我们的框架使用到弱引用又怀疑有内存泄漏,就可以从这个角度检查。

相关标签: java引用