时间:2017-11-27 08:55
人气:
作者:admin
本文讲的是彻底理解引用在 Android 和 Java 中的工作原理。
对于一个 Android 开发者,如果你不使用 WeakReferences,这是有问题的。
举个恰当的例子,几个月前,我发布了我的最后一本书 “Android High Performance”, 联席作者是 Diego Grancini。最热门的章节之一就是讨论 Android 的内存管理。在本章中,我们介绍了移动设备中内存的工作原理,内存泄漏是如何发生的,为什么这个是重要的,以及我们可以应用哪些技术来避开它们。因为我从开发 Android 起,就常常看到这么种倾向:轻视甚至无视一切与内存泄漏和内存管理相关的问题。已经满足开发需求了,为何要庸人自扰呢?我们总是急于开发新的功能,我们宁愿在下一个 Sprint 演示中呈现一些可见的东西,也不会关心那些没有人一眼就能看到的东西。
这无疑是导致技术债务一个活生生的例子。 我甚至可以补充地说,技术债务在现实世界中也有一些影响,那是我们不能用单元测试衡量的:失望,开发者间的摩擦,低质量的软件和积极性的丧失。这种影响难以衡量的原因是在于它们常常发生在长远的将来的某个时间点。这有点像政客:如果我只当政 8 年,为何我要烦心 12 年后将要发生的事呢?除了在软件开发,一切都以更快的方式。
编写软件开发中应该采纳的设计思想可能需要一些大篇文章,而且已经有很多书和文章可供您参考。然而,简要地解释不同类型的内存引用,它们具体是什么,以及如何在 Android 中使用,这是个相对简短的任务,这也是我想在本文中做的。
首先:Java 中的引用是什么?
引用指向了一个对象,你能通过引用访问对象。
Java 默认有 4 种类型的引用:强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference) 和虚引用(PhantomReference)。部分人认为只有强引用和弱引用两种类型的引用,而弱引用有两个层次的弱化。我们习惯于将生活中的一切事物归类,那种毅力堪比植物学家对植物的分类的。不论你觉得哪种分类更好,首先你需要去理解这些引用。然后你可以找出自己的分类。
各种引用都是什么意思?
StrongReference: 强引用是 Java 中最为常见的引用类型。任何时候,当我们创建了一个对象,强引用也同时被创建了。比如,当我们这么做:
MyObject object = new MyObject();
一个新的 MyObject 对象被创建,指向它的强引用保存在 object 中。你还在看吧? 嗯,更有意思的事情来了,这个 object 是可以强行到达的——意思就是,它可以通过一系列强引用找到,这将会阻止垃圾回收机制回收它,然而,这正是是我们最想要的。现在,我们来看个例子。
花几分钟,尝试去找可能出现问题的点。
现在呢?
AsyncTask 对象会在 Activity onCreate() 方法中创建并运行。但这里有个问题:内部类在它的整个生命周期中是会访问外部类。
如果 Activity 被 destroy 掉时,会发生什么? AsyncTask 仍然持有 Activity 的引用,所以 Activity 是不能被 GC 回收的。这就是我们所说的内存泄漏。
旁注 :以前,我曾经对合适的人进行访谈,我问他们如何创建内存泄漏,而不是询问内存泄漏的理论方面。这总是更有趣!
内存泄漏实际上不仅发生在 Activity 自身销毁的时候,配置的改变(译者注:比如横屏切换成竖屏)或系统需要更多的内存时,也可能系统强行销毁。如果 AsyncTask 复杂点(比如,持有 Activity 上的 View 的引用),它甚至会导致崩溃,因为 view 的引用是 null。(译者注:这个是直译过来的,可能对部分同学来说,不太好理解。我举个例子吧,比如 AsyncTask 中引用了 ProgressDialog,AsyncTask 运行时会显示 ProgressDialog,当横屏切成竖屏时,这时会出现崩溃。(╯^╰〉)
那么,要如何防止这种问题再次发生呢?我们接下来介绍另一种类型的引用: