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) 平等地对待,并在垃圾回收器中进行统一调度和管理。
分享到:
相关推荐
常见的面试中会有这么一道题,“谈谈强引用、 软引用、 弱引用、虚引用”。 A:强引用,通过new出来的都是强引用 Q:那弱引用呢? A:通过... Class Reference java.lang.Object java.lan
3.1 强引 3.2 软引 3.3 弱引 3. 4 假象引
中的新结构和特性的引用 接口和 Lambda 表达式 接口中的默认方法 Java 8 为接口引入了默认方法。 这些方法与类中的具体方法相同。 它们是用关键字 default 声明的。 interface INewInterface { void method1 (); ...
ava有四种引用类型,strongreference,softreference,weakreference,phantomreference。本篇文档主要的就是进阶的介绍和了解这四种引用类型的异同点,助于你对java的更好的学习理解
Java的4种引用类型: 他们分别是强引用(StrongReference),软引用(SoftReference),弱引用(WeakReference)以及PhantomReference(虚引用),他们被 GC回收的可能性从小到大排列。 强引用(StrongReference) 只要强引用...
本篇文章尝试从What、Why、How这三个角度来探索Java中的弱引用,理解Java中弱引用的定义、基本使用场景和使用方法。由于个人水平有限,叙述中难免存在不准确或是不清晰的地方,希望大家可以指出,谢谢大家:) 1....
JVM 垃圾收集对不同类型的引用的有一种不同的方法。java对于它的对象。仅仅存在有引。它会一直存在于内存中。... 在一般的 Java 程序中,见到多的是强引用(strong reference)。如 Date date = newDate(),date 是
Java 对多线程的支持与同步机制深受大家的喜爱,似乎看起来使用了synchronized 关键 字就可以轻松地解决多线程共享数据同步问题。...object reference(对象引用)、static 函数和class literals(类名称字面常量)身上。
尽管一切都“看作”对象,但操纵的标志符实际上是对象的一个“引用”(reference)。 例如:用遥控器(引用)来操纵电视机(对象)。 分析:1.改变音量,实际操控的是遥控器(引用) 2.四处走动,只要带着遥控器(引用)...
在Java8中,我们可以直接通过方法引用来简写lambda表达式中已经存在的方法,这种特性就叫做方法引用(Method Reference)。下面这篇文章主要给大家介绍了关于如何更好的使用Java8中方法引用的相关资料,需要的朋友可以...
引用(Reference)类型 52 存储器分配和布局 53 this引用 55 Java编码约定 56 运算符的优先级 58 升级和表达式的类型转换 62 独立实践 70 第五章:数组 71 学习目标 71 数组的描述 72 创建数组 72 多维数组 78 拷贝...
Reference Graph 和 Instance Detail:跟踪内存使用和对象引用; 垃圾回收分析:检测过多的短期对象和垃圾收集详情; Snapshot 比对:确定代码改变对内存使用的影响。 JProbe Coverage *JProbe Coverage 帮助开发...
其中 objectReference 是对象的一个引用,它可以是一个已生成的对象,也可以是能够生成对 象引用的表达式。 例如:我们用 Point p=newPoint();生成了类 Point 的对象 p 后,可以用 p.x,p.y 来访问该点的 x、y 坐标,...
如果 再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。 无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而...
MATLAB-to-Java 外部语言接口的一个已知限制是无法通过引用使用标准机制的 Java 方法传递原始类型的数组。例如,这里讨论了这一点: ...
详细讲解了Java的值传递和引用传递,英文版,易懂,配图片分析!!
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 提供两种不同的类型:引用类型和原始类型(或内置类型)。Int是java的原始数据类型,Integer是java为int提供的封装类。Java为每个原始类型提供了封装类。 原始类型封装类 booleanBoolean charCharacter byte...
JProfiler是一个全功能的Java剖析工具(profiler),JProfiler可以找到性能瓶颈、抓住...heap快照(snapshot)模式让未被引用(reference)的对象, 稍微被引用的对象、或在终结(finalization)序列的对象都会被移除