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

Java引用(reference)

阅读更多

Java引用(reference)

Java语言具备内存的回收机制。当某个对象不被引用时,内存回收机制将该对象销毁。但这种机制也导致了另一种问题,如果对某个对象的引用一直存在,该对象将无法被释放,即使内存不足的情况下。在某些情况,程序对某个对象是否被释放不是很重要的情况,为了保证系统的运行,释放这一类的对象,是很有必要的。Java为了解决这个问题,引入了java.lang.ref包,称为弱引用的类(相对通常的强引用而言)。

java.lang.ref包内类的对象可以指向其他对象,并且这些引用的存在不影响垃圾回收器对指向对象的回收。其好处是使用者可以保持对使用对象的引用,同时JVM还可以在内存不够时对指向的对象进行回收,因而这个包适合用来实现与缓存相关的应用,同时该包的类还提供在对象的“可达性”发生变化时,进行提醒的机制。

图1 java.lang.ref包的结构

 

图2 java.lang.ref包类的继承关系

 

Reference 是一个抽象类,SoftReference,WeakReference,PhantomReference 以及 FinalReference 都是继承它的具体实现类。

 

 

StrongReference

 

Java语言中对象都是在堆heap上分配,当对象不被引用时将被内存回收机制释放回heap中重用。通常所说的引用都叫强引用。例如string tag = new String(“Tag”); tag引用就为强引用,它具有以下特性:

可以直接访问目标对象

所指向的对象在任何时候都不会被系统回收

可能导致内存泄漏

 

相对于强引用来说,java.lang.ref包内的其它引用被称为“弱引用”。它们在某些条件下能被系统回收。

 

 

SoftReference

 

在这些“弱引用”中它最强,SoftReference所指向的对象,当没有强引用指向它时,会在内存中停留一段的时间,垃圾回收器会根据 JVM 内存的使用情况(内存的紧缺程度)以及 SoftReference 的 get() 方法的调用情况来决定是否对其进行回收。

 

SoftReference<Bean> bean = new SoftReference<Bean>(new Bean(“name”, 10));

System.out.println(bean.get());// “name:10”

 

软引用有以下特征:

使用 get() 方法取得对象的强引用从而访问目标对象。

所指向的对象按照 JVM 的使用情况(Heap 内存是否临近阈值)来决定是否回收。

可以避免 Heap 内存不足所导致的异常。

 

当垃圾回收器决定对其回收时,会先清空它的 SoftReference,此后所有SoftReference 的 get() 方法都将会返回 null,然后再调用对象的 finalize() 方法,并在下一轮 GC 中对其真正进行回收。

 

 

WeakReference

 

WeakReference是弱于SoftReference的引用类型。弱引用的特性和基本与软引用相似,区别就在于弱引用所指向的对象只要进行系统垃圾回收,不管内存使用情况如何,永远对其进行回收(get() 方法返回 null)。完全可以通过和 SoftReference 一样的方式来操作 WeakReference。

 

弱引用有以下特征:

使用 get() 方法取得对象的强引用从而访问目标对象。

一旦系统内存回收,无论内存是否紧张,弱引用指向的对象都会被回收。

也可以避免 Heap 内存不足所导致的异常。

 

PhantomReference

 

PhantomReference 是所有“弱引用”中最弱的引用类型。不同于软引用和弱引用,虚引用无法通过 get() 方法来取得目标对象的强引用从而使用目标对象,get() 被重写为永远返回 null。

虚引用主要被用来跟踪对象被垃圾回收的状态,通过查看引用队列中是否包含对象所对应的虚引用来判断它是否 即将被垃圾回收,从而采取行动。它并不被期待用来取得目标对象的引用,而目标对象被回收前,它的引用会被放入一个ReferenceQueue对象中,从而达到跟踪对象垃圾回收的作用。

所以具体用法和之前两个有所不同,它必须传入一个ReferenceQueue对象。当虚引用所引用对象被垃圾回收后,虚引用会被添加到这个队列中。

 

例如:

public static void main(String[] args) {

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

PhantomReference<String> referent = new PhantomReference<String>(

new String(“T”), refQueue);

System.out.println(referent.get());// null

 

System.gc();

System.runFinalization();

 

System.out.println(refQueue.poll() == referent); //true

}

 

对于引用回收方面,虚引用类似强引用不会自动根据内存情况自动对目标对象回收,Client 需要自己对其进行处理以防Heap内存不足异常。

 

虚引用有以下特征:

永远无法使用get()方法取得对象的强引用从而访问目标对象。

所指向的对象在被系统内存回收前,虚引用自身会被放入ReferenceQueue对象中从而跟踪对象垃圾回收。

不会根据内存情况自动回收目标对象。

 

另外值得注意的是,其实 SoftReference, WeakReference 以及 PhantomReference 的构造函数都可以接收一个 ReferenceQueue 对象。当 SoftReference 以及 WeakReference 被清空的同时,也就是 Java 垃圾回收器准备对它们所指向的对象进行回收时,调用对象的 finalize() 方法之前,它们自身会被加入到这个 ReferenceQueue 对象中,此时可以通过 ReferenceQueue 的 poll() 方法取到它们。而 PhantomReference 只有当 Java 垃圾回收器对其所指向的对象真正进行回收时,会将其加入到这个 ReferenceQueue 对象中,这样就可以追综对象的销毁情况。

 

 

FinalReference 以及 Finzlizer

 

FinalReference是java.lang.ref 里的一个不能被公开访问的类。FinalReference代表的正是 Java中的强引用。Bean bean = new Bean();在虚拟机的实现过程中,实际采用了 FinalReference类对其进行引用。而Finalizer,除了作为一个实现类外,更是在虚拟机中实现一个 FinalizerThread,以使虚拟机能够在所有的强引用被解除后实现内存清理。

首先,通过声明 FinalizerThread,并将该线程实例化,设置为守护线程后,加入系统线程中去。

 

static {

ThreadGroup tg = Thread.currentThread().getThreadGroup();

for (ThreadGroup tgn = tg;

tgn != null;

tg = tgn, tgn = tg.getParent());

 

Thread finalizer = new FinalizerThread(tg);

finalizer.setPriority(Thread.MAX_PRIORITY – 2);

finalizer.setDaemon(true);

finalizer.start();

}

 

在GC的过程中,当一个强引用被释放,由系统垃圾收集器标记后的对象,会被加入 Finalizer对象中的ReferenceQueue中去,并调用Finalizer.runFinalizer()来执行对象的finalize 方法。

 

private void runFinalizer() {

synchronized (this) {

if (hasBeenFinalized()) return;

remove();

}

 

try {

Object finalizee = this.get();

if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {

invokeFinalizeMethod(finalizee);

/* 注意,这里需要清空栈中包含该变量的的slot,

** 从而来减少因为一个保守的GC实现所造成的变量未被回收的假象 */

finalizee = null;

}

} catch (Throwable x) { }

super.clear();

}

 

注意,标记处所调用的invokeFinalizeMethod为native 方法,由于 finalize 方法在 Object 类中被声明为 protected,这里必须采用 native 方法才能调用。随后通过将本地强引用设置为空,以便使垃圾回收器清理内存。

通过这样的方法,Java 将四种引用对象类型:软引用 (SoftReference),弱引用 (WeakReference),强引用 (FinalReference),虚引用 (PhantomReference) 平等地对待,并在垃圾回收器中进行统一调度和管理。

分享到:
评论

相关推荐

    Java功底之Reference

    在Java编程语言中,`Reference`类是一个非常特殊且重要的概念,它超出了常规的引用类型,如`Object`或数组引用。`Reference`类及其子类主要用于处理对象的软引用、弱引用和虚引用,这些引用类型在内存管理,特别是...

    Java之reference-JAVA程序员JAVA工程师面试必看.pdf,这是一份不错的文件

    在Java编程语言中,"reference"是一个至关重要的概念,它涉及到对象的引用和内存管理。在Java的世界里,"Everything is Object",这意味着所有的数据都以对象的形式存在,而reference则是连接这些对象与程序代码的...

    Java引用总结--StrongReference、SoftReference、WeakReference、PhantomRef

    Java引用类型总结 Java从1.2版本开始引入了四种引用,分别是强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)和虚引用(PhantomReference)。这四种引用的级别由高到低依次为:强引用...

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

    在Java中,对象的引用方式对于内存管理和对象生命周期的控制至关重要。从JDK 1.2版本开始,Java引入了四种不同级别的引用:强引用(Strong Reference)、软...希望本文能够为您提供在Java引用类型的使用上清晰的指导

    java 常见的四种引用

    ### Java 常见的四种引用详解 #### 引言 在Java中,为了更好地管理对象的生命周期,从JDK 1.2开始引入了四种不同级别的引用类型:强引用、软引用、弱引用和虚引用。每种引用类型都有其特定的应用场景,通过灵活运用...

    java引用的demo

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

    从面试题中看java的Reference(引用)

    在Java中,引用被分为四种不同的类型:强引用、软引用、弱引用和虚引用,这些引用类型允许程序员对对象的可达性进行更精细的控制。 1. 强引用(Strong Reference): 强引用是最常见的引用类型,通过`new`关键字...

    java 引用相关文档

    这个“java 引用相关文档”可能包含了深入探讨Java引用的各种类型及其特性的内容。在这里,我们将详细讲解Java中的四种引用类型:强引用、软引用、弱引用和虚引用,以及它们在内存管理和垃圾收集中的作用。 1. **强...

    Java引用类型1

    Java提供了四种不同级别的引用类型:强引用、软引用、弱引用和虚引用(幻象引用),每种引用类型在内存管理中有不同的作用。 1. **强引用(Strong Reference)** - 强引用是最常见的引用类型,即通常的变量赋值。...

    Java中的强软弱虚引用

    为了更好地理解和控制对象的生命周期,Java提供了四种不同类型的引用:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)以及虚引用(Phantom Reference)。每种引用都有其特定的...

    Java Reference源码解析

    Java Reference源码解析 Java Reference是Java语言的一种机制,用于追踪对象的可达性和垃圾回收。Java Reference源码解析主要为大家详细解析了Java Reference源码,具有一定的参考价值,感兴趣的小伙伴们可以参考...

    Java的四种引用

    从JDK 1.2版本开始,Java引入了一种更为精细的引用类型管理机制,通过四种不同的引用类型:强引用、软引用、弱引用和虚引用,让开发者能够更加灵活地控制对象的生命周期。这种机制不仅提升了Java应用程序对内存使用...

    Java引用类型编程开发技术共13页.pdf.zip

    在这里,我们将对Java引用类型的一些关键知识点进行详细的阐述。 1. 类(Class):Java是一种面向对象的语言,类是创建对象的蓝图。它定义了对象的属性(数据成员)和行为(方法)。通过定义类,我们可以创建具有...

    spring-javaconfig-reference

    ### Spring JavaConfig 参考指南知识点详述 #### 关于文档 本文档为Spring JavaConfig参考指南,版本1.0.0.m3,版权属于2005-2008年的Rod Johnson、Costin Leau和Chris Beams。本文档主要分为三部分: 1. **介绍**...

    java中传值与传引用

    在Java编程语言中,函数调用时的参数传递方式有两种:传值(Passing by Value)和传引用(Passing by Reference)。虽然Java官方文档中并未明确指出有传引用这一概念,但在实际操作中,Java的行为类似于传引用,尤其...

    Java中弱引用软引用虚引用及强引用的区别Java开发Ja

    在Java编程语言中,引用类型是理解内存管理的关键概念之一。强引用、弱引用、软引用和虚引用是四种不同的引用强度,它们在垃圾回收机制中扮演着不同的角色。了解这些引用类型对于优化内存使用、防止内存泄漏以及合理...

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

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

    java的primitive和reference类.docx

    Java Primitive 与 Reference 类型详解 Java 作为一种面向对象的语言,数据类型可以分为两类:Primitive 类型和 Reference 类型。Primitive 类型包括数字和布尔类型,不被看做对象,而是被称为基本类型。Reference ...

    Java 中 Reference用法详解

    Java 中的 Reference 类型主要分为四种:强引用、软引用、弱引用和虚引用。这些引用类型在 Java 中的使用非常广泛,特别是在缓存、池化和垃圾回收机制中。 强引用(Strong Reference) 强引用是一种最普通的引用...

Global site tag (gtag.js) - Google Analytics