Java、Android引用类型

news/2024/11/28 4:10:09/

Java/Android中有四种引用类型,分别是:
Strong reference - 强引用
Soft Reference - 软引用
Weak Reference - 弱引用
Phantom Reference - 虚引用

不同的引用类型有着不同的特性,同时也对应着不同的使用场景。

Strong reference - 强引用

实际编码中最常见的一种引用类型。常见形式如:A a = new A();等。强引用本身存储在栈内存中,其存储指向对内存中对象的地址。一般情况下,当对内存中的对象不再有任何强引用指向它时,垃圾回收机器开始考虑可能要对此内存进行的垃圾回收。如当进行编码:a = null,此时,刚刚在堆中分配地址并新建的a对象没有其他的任何引用,当系统进行垃圾回收时,堆内存将被垃圾回收。

SoftReference、WeakReference、PhantomReference都是类java.lang.ref.Reference的子类。Reference作为抽象基类,定义了其子类对象的基本操作。Reference子类都具有如下特点:

  • Reference子类不能无参化直接创建,必须至少以强引用对象为构造参数,创建各自的子类对象;
  • 因为1中以强引用对象为构造参数创建对象,因此,使得原本强引用所指向的堆内存中的对象将不再只与强引用本身直接关联,与Reference的子类对象的引用也有一定联系。且此种联系将可能影响到对象的垃圾回收。

根据不同的子类对象对其指示对象(强引用所指向的堆内存中的对象)的垃圾回收不同的影响特点,分别形成了三个子类,即SoftReference、WeakReference和PhantomReference

Soft Reference - 软引用

软引用的一般使用形式如下:
A a = new A();
SoftReference srA = new SoftReference(a);
通过对象的强引用为参数,创建了一个SoftReference对象,并使栈内存中的wrA指向此对象。
此时,进行如下编码:a = null,对于原本a所指向的A对象的垃圾回收有什么影响呢?
先直接看一下下面一段程序的输出结果:

public class ReferenceTest {public static void main(String[] args) {A a = new A();SoftReference<A> srA = new SoftReference<A>(a);a = null;if (srA.get() == null) {System.out.println("a对象进入垃圾回收流程");} else {System.out.println("a对象尚未被回收" + srA.get());}// 垃圾回收System.gc();if (srA.get() == null) {System.out.println("a对象进入垃圾回收流程");} else {System.out.println("a对象尚未被回收" + srA.get());}}
}class A {}
输出结果为:
a对象尚未被回收A@4807ccf6
a对象尚未被回收A@4807ccf6

当 a = null后,堆内存中的A对象将不再有任何的强引用指向它,但此时尚存在srA引用的对象指向A对象。当第一次调用srA.get()方法返回此指示对象时,由于垃圾回收器很有可能尚未进行垃圾回收,此时get()是有结果的,这个很好理解。当程序执行System.gc();强制垃圾回收后,通过srA.get(),发现依然可以得到所指示的A对象,说明A对象并未被垃圾回收。那么,软引用所指示的对象什么时候才开始被垃圾回收呢?需要满足如下两个条件:
1.当其指示的对象没有任何强引用对象指向它;
2.当虚拟机内存不足时。
因此,SoftReference变相的延长了其指示对象占据堆内存的时间,直到虚拟机内存不足时垃圾回收器才回收此堆内存空间。

Weak Reference - 弱引用

同样的,软引用的一般使用形式如下:
A a = new A();
WeakReference wrA = new WeakReference(a);
当没有任何强引用指向此对象时, 其垃圾回收又具有什么特性呢?

public class ReferenceTest {public static void main(String[] args) {A a = new A();WeakReference<A> wrA = new WeakReference<A>(a);a = null;if (wrA.get() == null) {System.out.println("a对象进入垃圾回收流程");} else {System.out.println("a对象尚未被回收" + wrA.get());}// 垃圾回收System.gc();if (wrA.get() == null) {System.out.println("a对象进入垃圾回收流程");} else {System.out.println("a对象尚未被回收" + wrA.get());}}
}class A {}
输出结果为:
a对象尚未被回收A@52e5376a
a对象进入垃圾回收流程

输出的第一条结果解释同上。当进行垃圾回收后,wrA.get()将返回null,表明其指示对象进入到了垃圾回收过程中。因此,对弱引用特点总结为:
WeakReference不改变原有强引用对象的垃圾回收时机,一旦其指示对象没有任何强引用对象时,此对象即进入正常的垃圾回收流程。
那么,依据此特点,很可能有疑问:WeakReference存在又有什么意义呢?
其主要使用场景见于:当前已有强引用指向强引用对象,此时由于业务需要,需要增加对此对象的引用,同时又不希望改变此引用的垃圾回收时机,此时WeakReference正好符合需求,常见于一些与生命周期的场景中。

ReferenceQueue

对于SoftReference和WeakReference,还有一个构造器参数为ReferenceQueue,当SoftReference或WeakReference所指示的对象确实被垃圾回收后,其引用将被放置于ReferenceQueue中。注意上文中,当SoftReference或WeakReference的get()方法返回null时,仅是表明其指示的对象已经进入垃圾回收流程,此时对象不一定已经被垃圾回收。而只有确认被垃圾回收后,其引用才会被放置于ReferenceQueue中。

public static void main(String[] args) {A a = new A();ReferenceQueue referenceQueue = new ReferenceQueue();WeakReference<Object> weakReference = new WeakReference<Object>(a, referenceQueue);a = null;if(weakReference.get() == null){System.out.println("a对象进入垃圾回收流程");}else {System.out.println("a对象尚未被回收" + weakReference.get());}System.out.println("rq item:" + referenceQueue.poll());System.gc();if(weakReference.get() == null){System.out.println("a对象进入垃圾回收流程");}else {System.out.println("a对象尚未被回收" + weakReference.get());}System.out.println("rq item:" + referenceQueue.poll());}public static class A{@Overrideprotected void finalize() throws Throwable {System.out.println("A finalize");super.finalize();}}
输出结果为:
a对象尚未被回收@4554617c
rq item:null
a对象进入垃圾回收流程
rq item:null
A finalize

当调用System.gc()后,输出‘a对象进入垃圾回收流程’说明a已经开始进入了垃圾回收流程,但是还未被真正回收,因为Java对象被回收时会调用期finalize方法;此时我们立刻调用referenceQueue.poll()得到的是空,这样验证了对象只有gc已回收后WeakReference或SoftReference才会被加入ReferenceQueue。

现在我们再gc后,进行一段时间的延时后再调用referenceQueue.poll():
 public static void main(String[] args) {A a = new A();ReferenceQueue referenceQueue = new ReferenceQueue();WeakReference<Object> weakReference = new WeakReference<Object>(a, referenceQueue);a = null;if(weakReference.get() == null){System.out.println("a对象进入垃圾回收流程");}else {System.out.println("a对象尚未被回收" + weakReference.get());}System.out.println("rq item:" + referenceQueue.poll());System.gc();if(weakReference.get() == null){System.out.println("a对象进入垃圾回收流程");}else {System.out.println("a对象尚未被回收" + weakReference.get());}try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("rq item:" + referenceQueue.poll());}public static class A{@Overrideprotected void finalize() throws Throwable {System.out.println("A finalize");super.finalize();}}
输出结果
a对象尚未被回收@4554617c
rq item:null
a对象进入垃圾回收流程
A finalize
rq item:@74a14482

此时referenceQueue中存在了WeakReference,实验的结果也就不言而喻了。

PhantomReference虚引用

与SoftReference或WeakReference相比,PhantomReference主要差别体现在如下几点:

  • PhantomReference只有一个构造函数PhantomReference(T referent, ReferenceQueue<? super T> q),因此,PhantomReference使用必须结合ReferenceQueue;
  • 不管有无强引用指向PhantomReference的指示对象,PhantomReference的get()方法返回结果都是null。
public class ReferenceTest {public static void main(String[] args) {A a = new A();ReferenceQueue<A> rq = new ReferenceQueue<A>();PhantomReference<A> prA = new PhantomReference<A>(a, rq);System.out.println("prA.get():" + prA.get());a = null;System.gc();try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("rq item:" + rq.poll());}
}class A {}
输出结果为:
prA.get():null
rq item:java.lang.ref.PhantomReference@1da12fc0

代码中的Thread.sleep(1);作用与上例中相同,都是确保垃圾回收线程能够执行。否则,进进入垃圾回收流程而没有真正被垃圾回收的指示对象的虚引用是不会被加入到PhantomReference中的。

与WeakReference相同,PhantomReference并不会改变其指示对象的垃圾回收时机。ReferenceQueue的作用主要是用于监听Java对象是否已经被垃圾回收。

http://www.ppmy.cn/news/1550521.html

相关文章

Windows 系统上构建 Linux 应用

Red Hat 和 Microsoft 共同宣布&#xff0c;Red Hat Enterprise Linux&#xff08;RHEL&#xff09;即将成为微软 Windows Subsystem for Linux&#xff08;WSL&#xff09;的官方 Linux 发行版。 在 Windows 系统上构建 Linux 应用&#xff0c;然后在 RHEL 环境中部署的开发人…

【大数据学习 | Spark-Core】RDD的五大特性(包含宽窄依赖)

分析一下rdd的特性和执行流程 A list of partitions 存在一系列的分区列表A function for computing each split 每个rdd上面都存在compute方法进行计算A list of dependencies on other RDDs 每个rdd上面都存在一系列的依赖关系Optionally, a Partitioner for key-value RDDs…

深度学习实验十二 卷积神经网络(3)——基于残差网络实现手写体数字识别实验

目录 一、模型构建 1.1残差单元 1.2 残差网络的整体结构 二、统计模型的参数量和计算量 三、数据预处理 四、没有残差连接的ResNet18 五、带残差连接的ResNet18 附&#xff1a;完整的可运行代码 实验大体步骤&#xff1a; 先前说明&#xff1a; 上次LeNet实验用到的那…

在kali用msfpc远程控制Windows

本次实验我们将使用msfpc生成windows下的被控端&#xff0c;并使用metasploit渗透工具进行远程控制。 一、实验环境 Windows主机IP&#xff1a; 192.168.167.1 虚拟机Kali IP&#xff1a; 192.168.167.100 二、实验过程 1、安装msfpc apt-get install msfpc 2、生成windows…

AI产业告别“独奏”时代,“天翼云息壤杯”高校AI大赛奏响产学研“交响乐”

文 | 智能相对论 作者 | 陈泊丞 人工智能产业正在从“独奏”时代进入“大合奏”时代。 在早期的AI发展阶段&#xff0c;AI应用主要集中在少数几个领域&#xff0c;如语音识别、图像处理等。这些领域的研究和开发工作往往由少数几家公司或研究机构即可独立完成&#xff0c;犹…

PMP–一、二、三模、冲刺–分类–5.范围管理–技巧–引导

文章目录 技巧一模5.范围管理--3.定义范围--工具与技术--引导--在研讨会和座谈会中使用引导技能来协调具有不同期望或不同专业知识的关键干系人&#xff0c;使他们就项目可交付成果以及项目和产品边界达成跨职能的共识。引导&#xff1a;题干关键词 “需求不同、需求差异、需求…

MTK主板_安卓主板方案_MTK联发科主板定制开发

联发科(MTK)主板以其强大的性能和多样化的功能而受到广泛关注。该平台包括多个型号&#xff0c;例如MT6761、MT8766、MT6762、MT6765、MT8768和MT8788等&#xff0c;均配置了四核或八核64位处理器&#xff0c;主频可高达2.0GHz。采用先进的12nm工艺&#xff0c;搭载Android 11.…

自由学习记录(25)

只要有修改&#xff0c;子表就不用元表的参数了&#xff0c;用自己的参数&#xff08;只不过和元表里的那个同名&#xff09; 子表用__index“继承”了父表的值&#xff0c;此时子表仍然是空表 一定是创建这样一个同名的变量在原本空空的子表里&#xff0c; 传参要传具体的变…