`
hbxflihua
  • 浏览: 660375 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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

    博客分类:
  • java
阅读更多

 

  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 变量),那么对象可能就没有机会变回类似弱引用的可达性状态了,就会产生内存泄漏。所以,检查弱引用指向对象是否被垃圾收集,也是诊断是否有特定内存泄漏的一个思路,如果我们的框架使用到弱引用又怀疑有内存泄漏,就可以从这个角度检查。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics