Java的四种引用方式

摘要:
对Java对象的引用包括:强引用软引用弱引用虚拟引用Java提供这四种引用类型有两个目的:第一,它允许程序员通过代码确定某些对象的生命周期;第二个是方便JVM进行垃圾收集。SoftReference的特点是它的一个实例保存了对Java对象的软引用。软引用的存在不会阻止垃圾收集线程收集Java对象。使用ReferenceQueue清除丢失软引用对象的SoftReference:作为Java对象,SoftReference对象不仅具有保存软引用的特殊性,而且具有Java对象的通用性。

转载于:https://blog.csdn.net/linzhiqiang0316/article/details/88591907 

下面是部分介绍

WeakReference

根据注释我们也可以推测,如果你了解 Java 中的四种引用类型的话,强引用、软引用、弱引用、虚引用的话,应该可以理解如果使用前两者,对于 GC 的话并不合适,除非强引用置 null 手动通知 GC 回收否则会一直存在在线程生命周期中;而软引用的话,也仅当内存不够时才会回收;虚引用因其特性无法完成 ThreadLocalMap 的所需功能;所以使用 WeakReference 类型是出于 GC 考虑,当某个 ThreadLocal 已经没有强引用指向时,它被 GC 回收,那么它的 ThreadLocalMap 里对应的 Entry 的键值会随之失效。

java对象的引用包括:

强引用

软引用

弱引用

虚引用

Java中提供这四种引用类型主要有两个目的:

第一是可以让程序员通过代码的方式决定某些对象的生命周期;

第二是有利于JVM进行垃圾回收。

1.强引用

 是指创建一个对象并把这个对象赋给一个引用变量。

比如:

Object object =new Object();

String str ="hello";

 强引用有引用变量指向时永远不会被垃圾回收,JVM宁愿抛出OutOfMemory错误也不会回收这种对象。

public class Main { 

    public static void main(String[] args) { 

        new Main().fun1(); 

    } 

      

    public void fun1() { 

        Object object = new Object(); 

        Object[] objArr = new Object[1000]; 

 } 

当运行至Object[] objArr = new Object[1000];这句时,如果内存不足,JVM会抛出OOM错误也不会回收object指向的对象。不过要注意的是,当fun1运行完之后,object和objArr都已经不存在了,所以它们指向的对象都会被JVM回收。

  如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

比如Vector类的clear方法中就是通过将引用赋值为null来实现清理工作的:

2.软引用(SoftReference

如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;

如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。

软引用可用来实现内存敏感的高速缓存,比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性。  

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了。

使用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 

3.弱引用(WeakReference

  弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示。下面是使用示例:

public class test {  

    public static void main(String[] args) {  

        WeakReference<People>reference=new WeakReference<People>(new People("zhouqian",20));  

        System.out.println(reference.get());  

        System.gc();//通知GVM回收资源  

        System.out.println(reference.get());  

    }  

}  

class People{  

    public String name;  

    public int age;  

    public People(String name,int age) {  

        this.name=name;  

        this.age=age;  

    }  

    @Override  

    public String toString() {  

        return "[name:"+name+",age:"+age+"]";  

    }  

}  

输出结果: 

    [name:zhouqian,age:20]

    null

第二个输出结果是null,这说明只要JVM进行垃圾回收,被弱引用关联的对象必定会被回收掉。不过要注意的是,这里所说的被弱引用关联的对象是指只有弱引用与之关联,如果存在强引用同时与之关联,则进行垃圾回收时也不会回收该对象(软引用也是如此)。

比如:将代码做一点小更改:

package yinyong;  

  

import java.lang.ref.WeakReference;  

  

public class test {  

    public static void main(String[] args) {  

        People people=new People("zhouqian",20);  

        WeakReference<People>reference=new WeakReference<People>(people);//<span style="color:#FF0000;">关联强引用</span>  

        System.out.println(reference.get());  

        System.gc();  

        System.out.println(reference.get());  

    }  

}  

class People{  

    public String name;  

    public int age;  

    public People(String name,int age) {  

        this.name=name;  

        this.age=age;  

    }  

    @Override  

    public String toString() {  

        return "[name:"+name+",age:"+age+"]";  

    }  

}//结果发生了很大的变化  

[name:zhouqian,age:20]  

[name:zhouqian,age:20]  

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

4.虚引用(PhantomReference)

  虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。

要注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

import java.lang.ref.PhantomReference;  

import java.lang.ref.ReferenceQueue;  

public class Main {  

    public static void main(String[] args) {  

        ReferenceQueue<String> queue = new ReferenceQueue<String>();  

        PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);  

        System.out.println(pr.get());  

    }  

}  

软引用和弱引用

    对于强引用,我们平时在编写代码时经常会用到。而对于其他三种类型的引用,使用得最多的就是软引用和弱引用,这2种既有相似之处又有区别。它们都是用来描述非必需对象的,但是被软引用关联的对象只有在内存不足时才会被回收,而被弱引用关联的对象在JVM进行垃圾回收时总会被回收。

    在SoftReference类中,有三个方法,两个构造方法和一个get方法(WekReference类似):

两个构造方法:

public SoftReference(T referent) {  

    super(referent);  

    this.timestamp = clock;  

    }  

public SoftReference(T referent, ReferenceQueue<? super T> q) {  

    super(referent, q);  

    this.timestamp = clock;  

    }  

get方法用来获取与软引用关联的对象的引用,如果该对象被回收了,则返回null。

   在使用软引用和弱引用的时候,我们可以显示地通过System.gc()来通知JVM进行垃圾回收,但是要注意的是,虽然发出了通知,JVM不一定会立刻执行,也就是说这句是无法确保此时JVM一定会进行垃圾回收的。

免责声明:文章转载自《Java的四种引用方式》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇python 字典 拼接SQL语句iOS开发 弹簧效果下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

jvm之方法内联优化

前言 在日常中工作中,我们时不时会代码进行一些优化,比如用新的算法,简化计算逻辑,减少计算量等。对于java程序来说,除了开发者本身对代码优化之外,还有一个"人"也在背后默默的优化我们的代码,这个"人"就是jvm。jvm会帮我们分析出热点代码,优化代码逻辑。其中jvm最常做的优化之一就是:方法内联优化。 方法内联 什么是方法内联?又可以叫做函数内联,jav...

Java生产环境JVM设置成固定堆大小深层原理

  可能很多人都知道Java程序上生产后,运维人员都会设定好JVM的堆大小,而且还是把最大最小设置成一样的值。那究竟是为什么呢?一般而言,Java程序如果你不显示设定该值得话,会自动进行初始化设定。   -Xmx 的默认值为你当前机器最大内存的 1/4   -Xms 的默认值为你当前机器最大内存的 1/64    显然这样配置的意义是希望JVM可以根据当前...

JVM:查看java内存情况命令

  jmap (linux下特有,也是很常用的一个命令)   观察运行中的jvm物理内存的占用情况。   参数如下:   -heap :打印jvm heap的情况   -histo: 打印jvm heap的直方图。其输出信息包括类名,对象数量,对象占用大小。   -histo:live : 同上,但是只答应存活对象的情况   -permstat: 打印pe...

java 大数据处理之内存溢出解决办法(一)

http://my.oschina.net/songhongxu/blog/209951 一、内存溢出类型 1、java.lang.OutOfMemoryError: PermGen space JVM管理两种类型的内存,堆和非堆。堆是给开发人员用的上面说的就是,是在JVM启动时创建;非堆是留给JVM自己用的,用来存放类的信息的。它和堆不同,运行期内GC不...

mycat初识启动遇到的问题总结

1.Mycat 使用版本1.6.4,JDK使用1.7.0_79,启动时wrapper.log日志报错:Unable to locate the class io.mycat.MycatStartup STATUS | wrapper | 2021/02/09 15:34:54 | --> Wrapper Started as Daemon STATU...

执行sparksql出现OOM问题

一开始使用yarn-client模式提交作业时一切正常,但换成cluster模式下使用sparksql方法执行hive查询语句时,却出现了如下的OOM问题: Exception in thread "Thread-3" java.lang.OutOfMemoryError: PermGen space 出现这个错误原主要原因是太多的类或者太大的类都被加载...