`
thunder_yan
  • 浏览: 109375 次
  • 性别: 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(引用)

    常见的面试中会有这么一道题,“谈谈强引用、 软引用、 弱引用、虚引用”。  A:强引用,通过new出来的都是强引用  Q:那弱引用呢?  A:通过...  Class Reference  java.lang.Object  java.lan

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

    3.1 强引 3.2 软引 3.3 弱引 3. 4 假象引

    java8stream源码-Java-8-Reference:参考java8新特性

    中的新结构和特性的引用 接口和 Lambda 表达式 接口中的默认方法 Java 8 为接口引入了默认方法。 这些方法与类中的具体方法相同。 它们是用关键字 default 声明的。 interface INewInterface { void method1 (); ...

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

    ava有四种引用类型,strongreference,softreference,weakreference,phantomreference。本篇文档主要的就是进阶的介绍和了解这四种引用类型的异同点,助于你对java的更好的学习理解

    Java虚拟机(四)——Java引用对象4种类型

    Java的4种引用类型: 他们分别是强引用(StrongReference),软引用(SoftReference),弱引用(WeakReference)以及PhantomReference(虚引用),他们被 GC回收的可能性从小到大排列。 强引用(StrongReference) 只要强引用...

    理解Java中的弱引用(Weak Reference)

    本篇文章尝试从What、Why、How这三个角度来探索Java中的弱引用,理解Java中弱引用的定义、基本使用场景和使用方法。由于个人水平有限,叙述中难免存在不准确或是不清晰的地方,希望大家可以指出,谢谢大家:)  1....

    Java引用类型具体解释

    JVM 垃圾收集对不同类型的引用的有一种不同的方法。java对于它的对象。仅仅存在有引。它会一直存在于内存中。...  在一般的 Java 程序中,见到多的是强引用(strong reference)。如 Date date = newDate(),date 是

    Java同步机制浅谈

    Java 对多线程的支持与同步机制深受大家的喜爱,似乎看起来使用了synchronized 关键 字就可以轻松地解决多线程共享数据同步问题。...object reference(对象引用)、static 函数和class literals(类名称字面常量)身上。

    [java]读书笔记整理:一切都是对象

    尽管一切都“看作”对象,但操纵的标志符实际上是对象的一个“引用”(reference)。 例如:用遥控器(引用)来操纵电视机(对象)。 分析:1.改变音量,实际操控的是遥控器(引用) 2.四处走动,只要带着遥控器(引用)...

    如何更好的使用Java8中方法引用详解

    在Java8中,我们可以直接通过方法引用来简写lambda表达式中已经存在的方法,这种特性就叫做方法引用(Method Reference)。下面这篇文章主要给大家介绍了关于如何更好的使用Java8中方法引用的相关资料,需要的朋友可以...

    Java语言基础下载

    引用(Reference)类型 52 存储器分配和布局 53 this引用 55 Java编码约定 56 运算符的优先级 58 升级和表达式的类型转换 62 独立实践 70 第五章:数组 71 学习目标 71 数组的描述 72 创建数组 72 多维数组 78 拷贝...

    JAVA性能瓶颈和漏洞检测

    Reference Graph 和 Instance Detail:跟踪内存使用和对象引用; 垃圾回收分析:检测过多的短期对象和垃圾收集详情; Snapshot 比对:确定代码改变对内存使用的影响。 JProbe Coverage *JProbe Coverage 帮助开发...

    Java 语言基础 —— 非常符合中国人习惯的Java基础教程手册

    其中 objectReference 是对象的一个引用,它可以是一个已生成的对象,也可以是能够生成对 象引用的表达式。 例如:我们用 Point p=newPoint();生成了类 Point 的对象 p 后,可以用 p.x,p.y 来访问该点的 x、y 坐标,...

    Java synchronized详细解读.docx

    如果 再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。 无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而...

    JavaMethodWrapper:通过 Java 反射 API 促进原始数组到 Java 方法的传递引用行为。-matlab开发

    MATLAB-to-Java 外部语言接口的一个已知限制是无法通过引用使用标准机制的 Java 方法传递原始类型的数组。例如,这里讨论了这一点: ...

    Pass by value VS Pass by Reference

    详细讲解了Java的值传递和引用传递,英文版,易懂,配图片分析!!

    JProfiler 是一个全功能的Java剖析工具(profiler)

    JProfiler 是一个全功能的Java剖析工具...heap快照(snapshot)模式让未被引用(reference)的对象, 稍微被引用的对象、或在终结(finalization)序列的对象都会被移除;整合精灵以便剖析瀏览器的Java外掛功能

    值类型和引用类型的区别

    7: public static class ReferenceAndValue 8: { 9: public static void Demonstration() 10: { 11: Person zerocool = new Person { Name = "ZeroCool", Age = 25 }; 12: Person anders = new Person { Name ...

    java 面试题 总结

    Java 提供两种不同的类型:引用类型和原始类型(或内置类型)。Int是java的原始数据类型,Integer是java为int提供的封装类。Java为每个原始类型提供了封装类。 原始类型封装类 booleanBoolean charCharacter byte...

    YourKit.Java.Profiler.v9.0.3+注册机

    JProfiler是一个全功能的Java剖析工具(profiler),JProfiler可以找到性能瓶颈、抓住...heap快照(snapshot)模式让未被引用(reference)的对象, 稍微被引用的对象、或在终结(finalization)序列的对象都会被移除

Global site tag (gtag.js) - Google Analytics