垃圾收集的根本原因是,在像 C 这样的语言中,内存管理完全在程序员的显式控制之下,当对象所有权被传递时,特别是在线程之间,或者更难的是,在共享内存的进程之间,避免内存泄漏和悬空指针会变得非常困难。如果这还不够难,您还必须处理一次访问的对象数量超过内存容量的需求——您需要有一种方法可以在一段时间内释放一些对象,以便其他对象可以在内存中。
因此,某些语言(例如 Perl、Lisp、Java)提供了一种机制,您可以在其中停止“使用”一个对象,而垃圾收集器最终会发现这一点并释放用于该对象的内存。它可以正确地做到这一点,而程序员不必担心他们可能会出错的所有方式(尽管程序员可以通过多种方式搞砸)。
如果您从概念上将访问对象的次数乘以计算对象值所需的时间,并可能再次乘以对象不可用的成本或对象的大小,因为保持内存中的大对象可以防止保留几个较小的对象,您可以将对象分为三类。
有些对象非常重要,以至于您想显式地管理它们的存在——它们不会由垃圾收集器管理,或者在显式释放之前永远不能收集它们。有些对象计算成本低、体积小、访问不频繁或具有相似的特性,可以随时对它们进行垃圾回收。
第三类,重新计算代价高昂但可以重新计算的对象,被频繁访问(可能是短暂的时间),尺寸大,等等是第三类。您希望将它们尽可能长时间地保存在内存中,因为它们可能会再次被重用,但您不想耗尽关键对象所需的内存。这些是弱引用的候选者。
如果这些对象与关键资源不冲突,您希望它们尽可能长时间地保留,但如果关键资源需要内存,则应该删除它们,因为可以在需要时再次重新计算。这些是弱指针的用途。
这方面的一个例子可能是图片。假设您有一个包含数千张图片的照片网页要显示。您需要知道要布置多少张图片,也许您必须执行数据库查询才能获取列表。保存数千个项目的列表的内存可能非常小。您想执行一次查询并保留它。
但是,您一次只能在网页的窗格中实际显示几十张图片。您不需要为用户无法查看的图片获取位。当用户滚动页面时,您将收集可见图片的实际位。这些图片可能需要很多兆字节才能显示出来。如果用户在几个滚动位置之间来回滚动,您不想一遍又一遍地重新获取这些兆字节。但是你不能一直把所有的图片都保存在内存中。所以你使用弱指针。
如果用户只是一遍又一遍地看几张图片,它们可能会留在缓存中,而您不必重新获取它们。但是如果它们滚动得足够多,您需要释放一些内存以便可以获取可见图片。使用弱引用,您在使用它之前检查引用。如果它仍然有效,则使用它。如果不是,您需要进行昂贵的计算(获取)来获取它。