当我在LeakCanary 库的文档中阅读更多内容以了解其工作原理时,我第一次听说了弱引用。但是当我用谷歌搜索它时,我并没有完全明白。此外,我阅读的所有示例都不实用,这使得理解这个概念变得更加困难。
Java 中有 4 种类型的引用:Strong、Soft、Weak和Phatom。
在本文中,我们将重点关注强引用和弱引用。
强参考
每当我们创建任何对象时,它都是默认创建的引用。此引用将防止垃圾收集器 (GC) 销毁此对象。
例如,当我们创建一个名为Dummy;的类的实例时。如下图所示:
一个新类型的对象Dummy在内存中创建并myObject具有对其的强引用。
当我们在垃圾收集器运行myObject 之前尝试打印时;它将打印内存中对象的地址。
但是,当垃圾收集器运行时会发生什么?(我们通过写来强制GC运行来模拟这个System.gc())
对象将留在内存中,不会发生任何事情,因为这是我们所期望的(强引用防止 GC 破坏引用的对象)。
弱参考
这是来自维基百科的定义:
与强引用不同,弱引用是不保护被引用对象不被垃圾收集器收集的引用。
这意味着当我们创建一个对象的弱引用并且垃圾收集器运行时,它会立即从内存中清除该对象(如果没有其他对该对象的强引用)。
让我们举这个例子,然后我会解释什么时候我们可能需要这样的东西。
在上图中,我们创建了一个类型对象Dummy并对其myObject进行了弱引用。
所以在Dummy垃圾收集器运行之前,内存中现在有一个类型的对象,它是通过myObject使用弱引用来引用的。
我们现在将打印该虚拟对象,以确保它存在于内存中;对myObject变量使用.get()方法。
注意:该get()方法返回引用WeakReference的引用对象,如果引用的对象被清除,则返回 null。
所以Dummy我们创建的对象的内存地址会打印在控制台中,确认对象现在在内存中。
但是,如果我们现在运行垃圾收集器会发生什么?
在这里,您可以看到null已打印,并且Dummy实例已从内存中删除;这是有道理的,因为弱引用的描述表明,如果对对象存在弱引用并且垃圾收集器运行,它将从内存中删除该对象。
使用强引用和弱引用的示例
对于本例,我们有一个变量myObject,它保存对Dummy实例的强引用。
因此,让我们看看垃圾收集器运行之前和之后会发生什么。
在这里,Dummy()内存中的对象在 GC 运行后不会被销毁,因为有一个强引用( myObject) 来引用它。
而对于弱引用,它不会被 GC 清除,因为对象 ( Dummy()) 有另一个强引用( myObject) 附加到它上面。
这是弱引用的真正好处,它们只保留对对象的引用,只要它存在于内存中,并在与该对象相关的所有强引用都被清除时被清除。
Android 中的真实示例
我们都知道在单例中保留对上下文的引用是一个坏主意。如果您尝试这样做,Android Studio 会给您一个警告,说明:
不要将 Android 上下文类放在静态字段中(对 MySingleton 的静态引用,其中字段上下文指向 Context);这是内存泄漏
而这会导致内存泄漏。
那么,如何解决这个问题呢?
使用弱引用!
以下是如何使用它:
现在,警告消失了,因为它不会导致泄漏,因为当MainActivity实例被销毁(onDestroy被调用)时,对其上下文的弱引用也将被销毁;所以不会发生内存泄漏。
结论
在开发 Android 应用程序、库或任何 Java/Kotlin 项目时,WeakReference 是一个非常重要的概念;但是,您必须确保正确使用它,以避免在代码中出现任何意外行为。
文章来源:https://blog.ahmedashour.me/weak-references-in-java-kotlin-explained-with-illustrations-android







网友评论