`

深入理解 Java中的软引用,弱引用和虚引用

 
阅读更多

转载来源:http://my.eoe.cn/ymcao/archive/3623.html

Java中的软引用,弱引用和虚引用

 在Android的图片处理中,碰到的一个非常普遍的问题便是OOM错误 为此网上也有很多例子,而在之前的一篇转载里 提到了ListView中加载图片的ImageLoader,而其中有一处,使用到了名为SoftPreference的类 这是Java中的一个类 也就是所谓的软引用 在查询了相关的资料以后 会发现SoftPreference的特性,非常适合用来处理OOM引起的问题:

  SoftReference、Weak Reference和PhantomRefrence分析和比较

  本文将谈一下对SoftReference(软引用)、WeakReference(弱引用)和PhantomRefrence(虚引用)的理解,这三个类是对heap中java对象的应用,通过这个三个类可以和gc做简单的交互。

  强引用:

  除了上面提到的三个引用之外,还有一个引用,也就是最长用到的那就是强引用。例如:

Object o=new Object();

Object o1=o;

  上面代码中第一句是在heap堆中创建新的Object对象通过o引用这个对象,第二句是通过o建立o1到new Object()这个heap堆中的对象的引用,这两个引用都是强引用.只要存在对heap中对象的引用,gc就不会收集该对象.如果通过如下代码:

o=null;

o1=null;

  如果显式地设置o和o1为null,或超出范围,则gc认为该对象不存在引用,这时就可以收集它了。可以收集并不等于就一会被收集,什么时候收集这要取决于gc的算法,这要就带来很多不确定性。例如你就想指定一个对象,希望下次gc运行时把它收集了,那就没办法了,有了其他的三种引用就可以做到了。其他三种引用在不妨碍gc收集的情况下,可以做简单的交互。

  heap中对象有强可及对象、软可及对象、弱可及对象、虚可及对象和不可到达对象。应用的强弱顺序是强、软、弱、和虚。对于对象是属于哪种可及的对象,由他的最强的引用决定。如下:

String abc=new String("abc"); //1

SoftReference abcSoftRef=new SoftReference(abc); //2

WeakReference abcWeakRef = new WeakReference(abc); //3

abc=null; //4

abcSoftRef.clear();//5

  第一行在heap对中创建内容为“abc”的对象,并建立abc到该对象的强引用,该对象是强可及的。

  第二行和第三行分别建立对heap中对象的软引用和弱引用,此时heap中的对象仍是强可及的。

  第四行之后heap中对象不再是强可及的,变成软可及的。同样第五行执行之后变成弱可及的。

  SoftReference(软引用)

  软引用是主要用于内存敏感的高速缓存。在jvm报告内存不足之前会清除所有的软引用,这样以来gc就有可能收集软可及的对象,可能解决内存吃紧问题,避免内存溢出。什么时候会被收集取决于gc的算法和gc运行时可用内存的大小。当gc决定要收集软引用是执行以下过程,以上面的abcSoftRef为例:

  1、首先将abcSoftRef的referent设置为null,不再引用heap中的new String("abc")对象。

  2、将heap中的new String("abc")对象设置为可结束的(finalizable)。

  3、当heap中的new String("abc")对象的finalize()方法被运行而且该对象占用的内存被释放, abcSoftRef被添加到它的ReferenceQueue中。

  注:对ReferenceQueue软引用和弱引用可以有可无,但是虚引用必须有,参见:

Reference(T paramT, ReferenceQueue<? super T>paramReferenceQueue)

  被 Soft Reference 指到的对象,即使没有任何 Direct Reference,也不会被清除。一直要到 JVM 内存不足且 没有 Direct Reference 时才会清除,SoftReference 是用来设计 object-cache 之用的。如此一来 SoftReference 不但可以把对象 cache 起来,也不会造成内存不足的错误 (OutOfMemoryError)。我觉得 Soft Reference 也适合拿来实作 pooling 的技巧。

1
 A obj = new A();

SoftRefenrence sr = new SoftReference(obj);

1
2
3
4
5
6
7
//引用时
if(sr!=null){
    obj = sr.get();
}else{
    obj = new A();
    sr = new SoftReference(obj);
}

 弱引用

  当gc碰到弱可及对象,并释放abcWeakRef的引用,收集该对象。但是gc可能需要对此运用才能找到该弱可及对象。通过如下代码可以了明了的看出它的作用:

String abc=new String("abc");

WeakReference abcWeakRef = new WeakReference(abc);

abc=null;

System.out.println("before gc: "+abcWeakRef.get());

System.gc();

System.out.println("after gc: "+abcWeakRef.get());

  运行结果:

  before gc: abc
  after gc: null

  gc收集弱可及对象的执行过程和软可及一样,只是gc不会根据内存情况来决定是不是收集该对象。

  如果你希望能随时取得某对象的信息,但又不想影响此对象的垃圾收集,那么你应该用 Weak Reference 来记住此对象,而不是用一般的 reference。

A obj = new A();

1
2
3
4
5
WeakReference wr = new WeakReference(obj);

obj = null;

//等待一段时间,obj对象就会被垃圾回收

  ...

  if (wr.get()==null) {
  System.out.println("obj 已经被清除了 ");
  } else {
  System.out.println("obj 尚未被清除,其信息是 "+obj.toString());
  }
  ...
}

  在此例中,透过 get() 可以取得此 Reference 的所指到的对象,如果返回值为 null 的话,代表此对象已经被清除。

  这类的技巧,在设计 Optimizer 或 Debugger 这类的程序时常会用到,因为这类程序需要取得某对象的信息,但是不可以 影响此对象的垃圾收集。

  PhantomRefrence(虚引用)

  虚顾名思义就是没有的意思,建立虚引用之后通过get方法返回结果始终为null,通过源代码你会发现,虚引用通向会把引用的对象写进referent,只是get方法返回结果为null。先看一下和gc交互的过程在说一下他的作用。

  1 不把referent设置为null,直接把heap中的new String("abc")对象设置为可结束的(finalizable).

  2 与软引用和弱引用不同,先把PhantomRefrence对象添加到它的ReferenceQueue中,然后在释放虚可及的对象。

  你会发现在收集heap中的new String("abc")对象之前,你就可以做一些其他的事情。通过以下代码可以了解他的作用。

import java.lang.ref.PhantomReference;

import java.lang.ref.Reference;

import java.lang.ref.ReferenceQueue;

import java.lang.reflect.Field;

public class Test {

public static boolean isRun = true;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public static void main(String[] args) throws Exception {    
    String abc = new String("abc");    
    System.out.println(abc.getClass() + "@" + abc.hashCode());    
    final ReferenceQueue referenceQueue = new ReferenceQueue<String>();    
    new Thread() {    
        public void run() {    
            while (isRun) {    
                Object o = referenceQueue.poll();    
                if (o != null) {    
                    try {    
                        Field rereferent = Reference.class   
                                .getDeclaredField("referent");    
                        rereferent.setAccessible(true);    
                        Object result = rereferent.get(o);    
                        System.out.println("gc will collect:"   
                                + result.getClass() + "@"   
                                + result.hashCode());    
                    } catch (Exception e) {    

                        e.printStackTrace();    
                    }    
                }    
            }    
        }    
    }.start();    
    PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,    
            referenceQueue);    
    abc = null;    
    Thread.currentThread().sleep(3000);    
    System.gc();    
    Thread.currentThread().sleep(3000);    
    isRun = false;    
}    

}

  结果为:

  class java.lang.String@96354
  gc will collect:class java.lang.String@96354

 
分享到:
评论

相关推荐

    Java中的引用类型详解:强引用、软引用、弱引用与虚引用

    深入理解Java中的引用类型对于有效地管理内存和提高应用程序的性能至关重要。根据具体的场景,选择适当的引用类型是优化程序的关键一步。希望本文能够为您提供在Java引用类型的使用上清晰的指导

    拓胜技术专家教你如何深入理解Java四种引用类型

    Java中的四种引用类型是Java内存管理的重要组成部分,它们分别是强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)和虚引用(PhantomReference)。每种引用类型具有不同的特点和用途,...

    十分钟理解Java中的弱引用编程开发技术共3页.pdf.z

    在Java中,`java.lang.ref`包提供了三种不同类型的引用:强引用(Strong Reference)、软引用(Soft Reference)和弱引用(Weak Reference)。我们主要关注弱引用,它通过`WeakReference`类来实现。弱引用对象在创建...

    深入理解Java中的弱引用

    Java中的弱引用是一种特殊的引用类型,它允许程序员创建对对象的引用,但这些引用不会阻止对象被垃圾收集器回收。这种引用的引入主要是为了解决内存管理和缓存策略中的问题,尤其是在防止内存泄漏方面。 首先,我们...

    Java中的引用类型:深入理解与应用实践

    Java中的引用类型为开发者提供了灵活的对象...通过合理使用强引用、软引用、弱引用和虚引用,可以有效地管理内存,减少内存泄漏的风险,并提高程序的性能。开发者应该根据具体的应用场景和需求,选择合适的引用类型。

    referenceInJava:Java强引用,软引用,弱引用以及虚引用测试项目

    这个"referenceInJava"项目专注于探讨四种不同类型的引用:强引用、软引用、弱引用和虚引用。这些引用类型与垃圾收集(Garbage Collection, GC)机制密切相关,对于优化内存使用和防止内存泄漏至关重要。 1. **强...

    强应用软引用弱引用与垃圾收集的关系1

    本文将深入探讨强引用、软引用、弱引用以及幻象引用这四种引用类型,以及它们与垃圾收集的关系。 1. **强引用(Strong Reference)**: - 强引用是Java中最常见的引用类型,它代表了一个对象的直接访问路径。只要...

    Java对象及其引用的理解

    在Java编程语言中,对象和引用的理解是至关重要的,它们构成了Java程序的基础。本文将深入探讨Java中的对象、引用以及它们之间的关系,并结合值传递的概念进行解析。 首先,我们需要理解什么是Java对象。在Java中,...

    Java中对象与引用

    在Java编程中,深入理解对象与引用的概念对于掌握面向对象编程至关重要。本文将从以下几个方面详细解析对象与引用的基本概念及其相互间的关系。 #### 一、对象与引用的基础概念 **对象**: 在Java中,对象是类的一...

    深入理解JAVA虚拟机实用技巧案例讲解.ppt

    **深入理解JAVA虚拟机实用技巧案例讲解** Java虚拟机(JVM)是Java程序的核心运行环境,它负责解析字节码并执行Java程序。在实际开发中,了解JVM的工作原理和优化技巧对于提高程序性能至关重要。以下是一些关键知识...

    深入了解java 中的String

    深入了解Java中的String类是至关重要的,因为String在Java编程中占据着极其重要的位置。下面将对给定的信息进行深入分析: ### 1. String 类是 final 的,不可被继承 在Java中,`String` 类被声明为 `final` 类型...

    深入Java虚拟机(原书第2版).pdf【附光盘内容】

     作者以易于理解的方式深入揭示了java虚拟机的内部工作原理,深入理解这些内容,将对读者更快速地编写更高效的程序大有裨益!  本书共分20章,第1-4章解释了java虚拟机的体系结构,包括java栈、堆、方法区、执行...

    java 引用相关文档

    在Java编程语言中,引用是连接对象实例与内存空间的关键概念。这个“java 引用相关...通过阅读“java 引用相关文档”,开发者可以深入理解Java引用机制,提升对内存管理的掌控能力,从而编写出更加高效、稳定的代码。

    java引用的demo

    本示例“java引用的demo”将深入探讨四种不同类型的引用:强引用、软引用、弱引用和虚引用。这些引用类型对于理解和优化内存管理至关重要,特别是在Android开发中,因为良好的内存管理能够提升应用性能并防止内存...

    强,软,弱,虚1

    本文将深入探讨四种引用类型:强引用、软引用、弱引用和虚引用。 首先,我们来理解强引用(Strong Reference)。强引用是最常见的引用类型,它代表了程序中的普通对象引用。当一个对象被强引用指向时,该对象被认为...

    深入理解Java虚拟机笔记(带目录).docx

    深入理解 Java 虚拟机笔记 Java 虚拟机(JVM)是 Java 语言的运行环境,它负责解释和执行 Java 字节码。下面是 Java 虚拟机相关的知识点: 虚拟机内存结构 Java 虚拟机的内存结构主要包括以下几个部分: * 方法...

    深入理解Java虚拟机1

    深入理解Java虚拟机,首先要明白Java虚拟机(JVM)的角色和功能。JVM是Java平台的核心组成部分,它负责执行Java程序,提供了一个跨平台的运行环境。在Java的发展历程中,Classic VM作为世界上第一款商用的Java虚拟机...

    深入JAVA虚拟机 不那么完美的第二版.pdf.zip

    虽然《深入JAVA虚拟机》的第二版可能在物理形态上有些许不足,但其内容依然对理解JVM的运作机制有着重要的指导意义。学习这些知识点,有助于Java开发者提升代码的运行效率,解决内存问题,以及进行性能优化。

    Java的引用和函数参数传递

    ### Java的引用与函数参数传递详解 #### 一、Java中的引用基础 在Java中,对象的引用扮演着类似于其他编程语言(如C/C++)中指针的...希望本文能帮助读者更好地理解Java中的这些核心概念,并在实践中正确运用它们。

Global site tag (gtag.js) - Google Analytics