java的引用分为四个等级:4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。

⑴强引用(StrongReference)

强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。  ps:强引用其实也就是我们平时A a = new A()这个意思。



⑵软引用(SoftReference)

如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存(下文给出示例)。

软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。



⑶弱引用(WeakReference)

弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。



⑷虚引用(PhantomReference)

“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。

ReferenceQueue queue = new ReferenceQueue ();

PhantomReference pr = new PhantomReference (object, queue); 



程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

使用软引用构建敏感数据的缓存

1 为什么需要使用软引用



首先,我们看一个雇员信息查询系统的实例。我们将使用一个Java语言实现的雇员信息查询系统查询存储在磁盘文件或者数据库中的雇员人事档案信息。作为一个用户,我们完全有可能需要回头去查看几分钟甚至几秒钟前查看过的雇员档案信息(同样,我们在浏览WEB页面的时候也经常会使用“后退”按钮)。这时我们通常会有两种程序实现方式:一种是把过去查看过的雇员信息保存在内存中,每一个存储了雇员档案信息的Java对象的生命周期贯穿整个应用程序始终;另一种是当用户开始查看其他雇员的档案信息的时候,把存储了当前所查看的雇员档案信息的Java对象结束引用,使得垃圾收集线程可以回收其所占用的内存空间,当用户再次需要浏览该雇员的档案信息的时候,重新构建该雇员的信息。很显然,第一种实现方法将造成大量的内存浪费,而第二种实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包含雇员档案信息的对象仍然完好地保存在内存中,应用程序也要重新构建一个对象。我们知道,访问磁盘文件、访问网络资源、查询数据库等操作都是影响应用程序执行性能的重要因素,如果能重新获取那些尚未被回收的Java对象的引用,必将减少不必要的访问,大大提高程序的运行速度。



2 如果使用软引用

SoftReference的特点是它的一个实例保存对一个Java对象的软引用,该软引用的存在不妨碍垃圾收集线程对该Java对象的回收。也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。另外,一旦垃圾线程回收该Java对象之后,get()方法将返回null。

看下面代码:

MyObject aRef = new

MyObject();

SoftReference aSoftRef=new SoftReference(aRef); 



此时,对于这个MyObject对象,有两个引用路径,一个是来自SoftReference对象的软引用,一个来自变量aReference的强引用,所以这个MyObject对象是强可及对象。

随即,我们可以结束aReference对这个MyObject实例的强引用:

aRef = null;

此后,这个MyObject对象成为了软可及对象。如果垃圾收集线程进行内存垃圾收集,并不会因为有一个SoftReference对该对象的引用而始终保留该对象。Java虚拟机的垃圾收集线程对软可及对象和其他一般Java对象进行了区别对待:软可及对象的清理是由垃圾收集线程根据其特定算法按照内存需求决定的。也就是说,垃圾收集线程会在虚拟机抛出OutOfMemoryError之前回收软可及对象,而且虚拟机会尽可能优先回收长时间闲置不用的软可及对象,对那些刚刚构建的或刚刚使用过的“新”软可反对象会被虚拟机尽可能保留。在回收这些对象之前,我们可以通过:

MyObject anotherRef=(MyObject)aSoftRef.get(); 



重新获得对该实例的强引用。而回收之后,调用get()方法就只能得到null了。



3 使用ReferenceQueue清除失去了软引用对象的SoftReference

作为一个Java对象,SoftReference对象除了具有保存软引用的特殊性之外,也具有Java对象的一般性。所以,当软可及对象被回收之后,虽然这个SoftReference对象的get()方法返回null,但这个SoftReference对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。在java.lang.ref包里还提供了ReferenceQueue。如果在创建SoftReference对象的时候,使用了一个ReferenceQueue对象作为参数提供给SoftReference的构造方法,如:

ReferenceQueue queue = new

ReferenceQueue();

SoftReference

ref=new

SoftReference(aMyObject, queue); 



那么当这个SoftReference所软引用的aMyOhject被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue。也就是说,ReferenceQueue中保存的对象是Reference对象,而且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也可以看出,它是一个队列,当我们调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象。

在任何时候,我们都可以调用ReferenceQueue的poll()方法来检查是否有它所关心的非强可及对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。利用这个方法,我们可以检查哪个SoftReference所软引用的对象已经被回收。于是我们可以把这些失去所软引用的对象的SoftReference对象清除掉。常用的方式为:

SoftReference ref = null;

while ((ref = (EmployeeRef) q.poll()) != null) {

// 清除ref

}

java的四种引用类型的更多相关文章

  1. java中四种引用类型

    java中四种引用类型  今天看代码,里面有一个类java.lang.ref.SoftReference把小弟弄神了,试想一下,接触java已经有3年了哇,连lang包下面的类都不了解,怎么混.后来在 ...

  2. Java的四种引用类型之弱引用

    先说结论: 首先,Java中有四种引用类型:强引用.软引用.弱引用.虚引用.-- 在 Java 1.2 中添加的,见 package java.lang.ref; . 其次,这几个概念是与垃圾回收有关 ...

  3. java中四种引用类型(对象的强、软、弱和虚引用)

    对象的强.软.弱和虚引用在JDK 1.2以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象.也就是说,只有对象处于可触及(reachable)状态,程序才能使用它.从JDK 1.2 ...

  4. 你知道Java的四种引用类型吗

    关于java四种引用类型,我也是刚了解,特此记下! 在Java中提供了四个级别的引用:强引用,软引用,弱引用和虚引用.在这四个引用类型中,只有强引用FinalReference类是包内可见,其他三种引 ...

  5. java中四种引用类型(转)

    今天看代码,里面有一个类java.lang.ref.SoftReference把小弟弄神了,试想一下,接触java已经有3年了哇,连lang包下面的类都不了解,怎么混.后来在网上查资料,感觉收获颇多, ...

  6. Java魔法堂:四种引用类型、ReferenceQueue和WeakHashMap

    一.前言 JDK1.2以前只提供一种引用类型——强引用 Object obj = new Object(); .而JDK1.2后我们多另外的三个选择分别是软引用 java.lang.ref.SoftR ...

  7. java基础之 数据类型 & 值传递 引用传递 & String & 四种引用类型

    一.Java数据类型 分为基本数据类型与引用数据类型 基本数据类型: byte:Java中最小的数据类型,在内存中占1个字节(8 bit),取值范围-128~127,默认值0 short:短整型,2个 ...

  8. java四种引用类型以及使用场景详解

    每种编程语言都有自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java 中则是通过“引用”.在 Java 中一切都被视为了对象,但是我们操作的标识符实际上是对象的一个引用(re ...

  9. Java中的四种引用类型比较

    1.引用的概念 引用这个概念是与JAVA虚拟机的垃圾回收有关的,不同的引用类型对应不同的垃圾回收策略或时机. 垃圾收集可能是大家感到难于理解的较难的概念之一,因为它并不能总是毫无遗漏地解决Java运行 ...

随机推荐

  1. 2015 多校联赛 ——HDU5348(搜索)

    Problem Description As we all kown, MZL hates the endless loop deeply, and he commands you to solve ...

  2. hdu 5479(括号问题)

    题意:类似"()","(())","()()" 是匹配的, 而 "((", ")(", " ...

  3. hdu 5505(GT and numbers)

    题意: 给你a和b,a每次和它的因子相乘得到一个新的a,求多少次后可以得到b. 输入样例 3 1 1 1 2 2 4 输出样例 0 -1 1 思路: 每次找出a和b/a的最大公约数(即当前a想得到b能 ...

  4. java处理数据库不支持的emoji

    一般数据库的编码是utf8,utf8是不支持存储表情符的,当存入的微信昵称带有表情符时就会出现乱码情况,有两种解决方法: 1.mysql数据库升级到5.5版本以上,utf8改为utf8mb4,utf8 ...

  5. 关于一些基础的Java问题的解答(五)

    21. 实现多线程的两种方法:Thread与Runable 在Java中实现多线程编程有以下几个方法: 1.继承Thread类,重写run方法 public class Test { public s ...

  6. python3获取网页天气预报信息并打印

    查到一个可以提供区域天气预报的url, https://www.sojson.com/open/api/weather/json.shtml?city=%E6%88%90%E9%83%BD打算用pyt ...

  7. ServiceStack 简单服务搭建

    1:定义数据实体 因为ServiceStack是基于请求参数来定义请求路由的,所以关键的是请求参数一定要定义好,同时可以在请求参数上自定义路由名和请求方式,作为对外接口名 上代码: namespace ...

  8. python类(class)中参数self的解释说明

    python类(class)中参数self的简单解释 1.self只有在类的方法中才会有,其他函数或方法是不必带self的. 2.在调用时不必传入相应的参数.3.在类的方法中(如__init__),第 ...

  9. beta 分布的详细介绍(转载)

    目前看到的关于beta分布最好的一个解释,由于贴过来格式不好看,所以附上链接: http://www.datalearner.com/blog/1051505532393058

  10. 关于bedtools merge 功能中sort 命令的解释

    Bedtools 是一个很好的用来处理区间的工具,很多时候用这个底层语言编写的小工具比自己写的脚本运行快很多,但是这个工具中的某些功能对输入文件有一定的要求,比如说里面的一个merge函数,这是里面的 ...