Java 引用的强软弱虚

编程入门 行业动态 更新时间:2024-10-09 11:21:55

Java 引用的强<a href=https://www.elefans.com/category/jswz/34/1712413.html style=软弱虚"/>

Java 引用的强软弱虚

Java 的引用的类型有四种:强引用、软引用、弱引用和虚引用。它们背后关系到 JVM 的垃圾回收机制回收内存的时机。

提前声明以下,这是纯理论概念,我们日常写代码的时候并不会涉及到软弱虚引用,通常只会涉及到强引用。

强软弱虚四种类型的引用的概念其实并非 Java 语言所特有,例如,苹果公司的 Objective-C 语言中同样也有一样的概念。

1. Objective-C 中的引用计数

苹果公司的 Objective-C 语言是没有垃圾回收机制的,那么为了解决回收内存行为不当所造成的内存泄露和 double free 问题,苹果公司为 Objective-C 语言引入了『引用计数』的概念,并将指针类型细化为强弱指针两种。

为了便于大家类比,我们后文就将 OC 中的指针「不严谨地」称为引用,将分配在堆空间的内存「不严谨地」称为对象。

Objective-C 的编译器在编译 OC 源码的时候会去记录、统计一个对象的引用的数量,这个值也就是这个对象的『引用计数』。

当没有任何一个引用指向这个对象时,即这个对象的引用计数变为 0 时,编译器会在导致引用计数从 1 变为 0 的那条语句的后面,『帮』你加上一条释放内存空间的语句。

通过这样一种 记录、统计对象的引用计数 + 『帮』你加释放内存的代码 从而实现帮助 OC 程序员释放内存,管理内存空间,达到避免内存泄漏和 double free 的目的。

那这和『强弱引用』有什么关系?

并不是所有的引用都会导致对象的引用计数 +1 。

如果是一个强引用指向了对象,那么对象的引用计数 +1,如果是一个弱引用指向了对象,那么对象的引用计数不受影响。

伪代码如下:

__strong Student tom = new Student(); // 1
__strong Student jerry = tom; // 2
__weak Student lucy = tom; // 3
__weak Student lily = jerry; // 4
tom = null; // 5
jerry = null; // 6

以上的代码中,有且仅有一个对象,而 tom、jerry、lucy 和 lily 是四个引用类型变量,它们都指向的是同一个对象。

代码1 执行完后,Student 对象的引用计数为 1;代码2执行完后,Student 对象的引用计数 +1 变为 2,因为此时有两个强引用指向了这个对象;

代码3 和 代码4 执行完后,Student 对象的引用计数仍然为 2,因为,即便 lucy 和 lily 这两个引用确实指向的是这个对象,但是谁叫它们「低人一等」是 弱引用 呢。

代码5 执行完后,Student 对象的引用计数从 2 降为 1,因为此时,只有 jerry 这一个强引用指向了 Student 对象;而 代码6 执行完后,Student 对象的引用计数就将为了 0 。

在 OC 的编译器编译源码时,它会在 代码6 之后『帮』我们加上一句释放 Student 对象所占内存空间的语句,即释放内存空间。

在内存和释放后,lucy 和 lily 这两个引用类型的变量实际上就指向了一块已回收的存空间,这个时候,你再通过 lucy.xxx 和 lily.xxx 来操作、访问这块内存空间的话,就会报运行时错误(大名鼎鼎的 Segment Fault)。

2. Java 中的强引用

Java 语言没有引用计数的概念,但是 Java 中的强弱引用的概念和 OC 中的强弱引用的概念是一模一样的。

强引用会影响对象被垃圾回收机制回收;而弱引用则对内存的回收无影响。

我们日常编码所涉及到的引用全部都是强引用,例如:

Student tom = new Student(); 
Student jerry = tom;
Student lucy = tom;
Student lily = jerry;

上述代码中,有 4 个引用指向了同一个对象。只要至少还存在一个引用指向这个对象,那么,这个 Student 对象的内存空间就不会被 JVM 回收。

最极端的情况下,如果所有的对象都至少存在一个强引用指向它,而随着系统中的对象越来越多,到最后内存不够用了,JVM 会抛出 OutOfMemoryError 异常。

JVM 哪怕最后「忍无可忍」抛出异常,它也一定不会回收仍然被使用的对象所占据的内容空间。逻辑上,也理应如此。

3. Java 中的软引用和弱引用

和 OC 中的弱引用一样,Java 中的软弱引用也「低人一等」。软弱引用不会影响到 Java 的垃圾回收机制回收内存。

但是,软引用又比弱引用要「高」半个身位。

Java 中的软引用

Student tom = new Student();
SoftReference<Student> jerry = new SoftReference<>(tom);tom = null;

上述代码中的 jerry 就是一个弱引用。理论上,当 tom = null 之后,Student 对象就应该被垃圾回收机制回收。

不过「理论是理论,现实是现实」,在 tom = null 之后还有一些「小故事」。

「故事一」,JVM 的垃圾回收机制并不是时时刻刻保持运行的。由于垃圾回收器是一个优先级很低的线程,所以 JVM 的垃圾回收器是「间歇性、间歇性地起来干活」的。

另外,现在的 JVM 机制中,你手动调用 System.gc(); JVM 也不保证垃圾回收器立刻起来干活。

因此,在你的 tom = null 之后,即便是 Student 对象没有强引用指向了,即逻辑上没人用了,但是实际上它还是要在内存中存在一段时间的。

「故事二」,即便是「软引用低人一等」,但是,JVM 的垃圾回收器仍让会对有软引用指向的对象网开一面。如果内存还有「富余」,垃圾回收器就不会回收软引用所指向的内存的对象。

也就是说,垃圾回收器的逻辑的伪代码类似如下:

if (对象.强引用数 == 0) { // 准备释放内存if (对象.软引用数 != 0 && 内存够用) {   // 网开一面暂不释放对象内存;}else {释放对象内存;}
}

Java 中的弱引用

Student tom = new Student();
WeakReference<Student> jerry = new WeakReference<>(tom);

弱引用就没有软引用那么好命,JVM 的垃圾回收器不会对它网开一面,只要对象的没有强引用了,无论有多少弱引用指向这个对象,也无论此时内存够不够用,JVM 的垃圾回收器都会回收内存。

从这个角度看,其实你可以将 软引用 看做是 弱引用 的一种特殊情况。软引用是会被垃圾回收器网开一面的弱引用。

不过,考虑上面所提到的垃圾回收器是一个优先级很低的线程,因此一个只有弱引用指向的对象,它还是有一段时间苟延残喘的:垃圾回收器还没起来干活,还没发现它。

Java 中的虚引用

虚引用和弱引用一样,它不影响垃圾回收器回收内存。一个仅有虚引用的对象,一旦被垃圾回收器发现,就会被回收内存。

虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用的级别比弱引用更低:弱引用 可以 和引用队列(ReferenceQueue)联合使用;而虚引用 只能 和引用队列联合使用。

扩展:为什么 OC 会提出弱引用的概念?

Objective-C 的引用计数的概念可以帮助大家理解垃圾回收的概念,但是大家有没有发现,如果只有强引用的概念,仅凭对象的强引用的计数来决定这个对象是否应该被销毁,回收内存,会有一个问题:循环引用 。

例如,有如下两个类定义:


class Husband {...private Wife wife;...
}class Wife {...private Husband husband;...
}

如果有丈夫、妻子两个对象互相引用,会出现什么问题?

Husband tom = new Husband();
Wife jerry = new Wife();tom.setWife(jerry);
jerry.setHusband(tom);

因为 tom 和 jerry 互相持有对方的一个强引用,因此,在 OC 中 丈夫和妻子对象的引用计数永不为 0 ,这就是『循环引用』。这种情况下,靠 OC 的编译器去『帮』我们加释放内存的代码,编译器是不会『帮』这个忙的,在它看来,这两个对象『还在被使用』啊?!

对于这种情况,就只能靠程序员自己调用 free() 手动释放。

当然,这只是最简单的循环引用情况,更复杂一点的可能是 A->B->C->D->E->A 这么一大圈的循环引用。

所有,这种情况下,OC 引入弱引用的概念,将两者中的某一方所持有的对方的引用从强引用改为弱引用,让整个『圈』中的某一个对象的引用计数能够变为 0,从而从它开始逐个释放掉整个『圈』中的各个对象的内存,进而解决这个循环依赖引用问题。


当然,在 Java 中我们不用考虑这个问题,因为判断多个对象之间是否存在循环引用问题,这个事情 JVM 的垃圾回收器它自己就干了,不需要我们像 OC 一样『亲自』通过弱引用来解决这个问题。

这也是我们日常编码中用不上软弱虚引用的原因。

更多推荐

Java 引用的强软弱虚

本文发布于:2024-03-05 13:30:21,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1712415.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:软弱   Java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!