我以前从未听说过弱指针。虽然我想支持我的语言中的多种功能,但在这种情况下,我实在想不出有用的场景。那么,人们将如何使用弱指针呢?弱指针类似于指针,但是由于来自弱指针的引用不会阻止垃圾回收,因此在使用弱指针之前必须检查其有效性。
弱指针与垃圾回收器交互,因为它们所指向的内存可能仍然有效,但是包含的内容可能与创建弱指针时不同。因此,每当垃圾回收器回收内存时,它必须检查是否有任何弱指针指向它,并将它们标记为无效(这不一定要以如此幼稚的方式实现)。
我以前从未听说过弱指针。虽然我想支持我的语言中的多种功能,但在这种情况下,我实在想不出有用的场景。那么,人们将如何使用弱指针呢?弱指针类似于指针,但是由于来自弱指针的引用不会阻止垃圾回收,因此在使用弱指针之前必须检查其有效性。
弱指针与垃圾回收器交互,因为它们所指向的内存可能仍然有效,但是包含的内容可能与创建弱指针时不同。因此,每当垃圾回收器回收内存时,它必须检查是否有任何弱指针指向它,并将它们标记为无效(这不一定要以如此幼稚的方式实现)。
一个典型的用例是存储额外的对象属性。假设您有一个具有固定成员集的类,而且您想要从外部添加更多成员。因此,您创建了一个字典对象 -> 属性,其中键是弱引用。然后,字典不会阻止键被垃圾回收;对象的删除也应该触发WeakKeyDictionary中值的删除(例如通过回调函数)。
另一个例子......不完全是缓存,但类似:假设一个I/O库提供了一个对象,它包装了一个文件描述符并允许访问该文件。当对象被收集时,文件描述符会被关闭。希望能够列出所有当前打开的文件。如果您对此列表使用强指针,则文件永远不会关闭。
当您希望保留对象的缓存列表但不阻止这些对象被垃圾回收时,请使用它们,如果对象的“真实”所有者完成,则可以进行垃圾回收。
Web浏览器可能会具有历史记录对象,该对象保留对浏览器在其他地方加载并保存在历史记录/磁盘缓存中的映像对象的引用。 Web浏览器可能会过期其中一个图像(用户清除了缓存,缓存超时已过等),但页面仍将具有引用/指针。 如果页面使用弱引用/指针,则对象将按预期消失,并且内存将被垃圾收集。
弱指针可以防止它们所指向的对象成为“生命支持系统”的形式。
假设您有一个Viewport类、两个UI类和一堆Widget类。您希望您的UI控制其创建的小部件的生命周期,因此您的UI保留了对所有受其控制的小部件的SharedPtrs。只要您的UI对象存在,它引用的任何小部件都不会被垃圾回收(感谢SharedPtr)。
但是,Viewport是实际执行绘图的类,因此您的UI需要将指向小部件的指针传递给Viewport以便它可以绘制它们。出于某种原因,您想将活动UI类更改为另一个UI类。让我们考虑两种情况,一种是UI传递了Viewport WeakPtrs,另一种是传递了SharedPtrs(指向小部件)。
如果您将所有小部件作为WeakPointers传递给Viewport,那么一旦删除UI类,就不会再有SharedPtrs指向小部件,因此它们将被垃圾回收,Viewport对对象的引用也不会使它们保持在“生命支持系统”上,这正是您想要的,因为您甚至不再使用该UI,更不用说它创建的小部件了。
现在,假设您已经将一个SharedPointer传递给了Viewport,您删除了UI,但Widget并没有被垃圾回收!为什么?因为Viewport仍然存在一个数组(向量或列表等),其中包含指向Widget的SharedPtr。实际上,Viewport已成为它们的一种“生命支持”,即使您已经删除了控制另一个UI对象的Widget的UI。拥有弱引用的一个重要原因是为了处理对象可能作为管道连接信息或事件源到一个或多个监听器的情况。如果没有任何监听器,就没有理由继续向管道发送信息。
例如,考虑一个可枚举集合,在枚举期间允许更新。该集合可能需要通知任何活动的枚举器它已经被更改,以便这些枚举器可以相应地调整自己。如果一些枚举器被其创建者抛弃,但集合对它们持有强引用,那么只要集合存在,这些枚举器将继续存在(并处理更新通知)。如果集合本身将在应用程序的生命周期内存在,那么这些枚举器将成为永久性的内存泄漏。
如果集合对枚举器持有弱引用,这个问题可以在很大程度上得到解决。如果枚举器被抛弃,即使集合仍然对它持有弱引用,它也将有资格进行垃圾回收。下次集合被更改时,它可以查看其弱引用列表,向仍然有效的枚举器发送更新,并从列表中删除无效的枚举器。
使用终结器和一些额外的对象可以实现许多弱引用的效果,而且可能使这样的实现比使用弱引用更高效,但是存在许多陷阱,很难避免错误。使用WeakReference可以更容易地实现正确的方法。该方法可能不是最优化的效率,但不会出现严重故障。
弱引用可以在缓存场景中使用 - 通过弱引用可以访问数据,但如果长时间不访问数据或内存压力较大,则垃圾回收器可以释放它。
因此,一些语言(例如Perl、Lisp、Java)提供了一种机制,您可以停止“使用”对象,垃圾收集器最终会发现这一点,并释放用于对象的内存。它可以正确地执行此操作,而无需程序员担心他们可能犯错的所有方式(尽管程序员可能会出现很多错误)。
如果您将访问对象的次数概念性地乘以计算对象值所需的时间,可能再乘以没有准备好对象的成本或对象的大小,因为在内存中保留大型对象可能会防止保留几个较小的对象,那么您可以将对象分类为三类。
有些对象非常重要,您希望明确地管理它们的存在——它们不会由垃圾回收器管理,或者必须在显式释放之前永远不会被回收。有些对象计算成本低廉,体积小,访问频率不高,或具有类似的特征,使它们可以随时进行垃圾回收。
第三类是那些重新计算成本高昂但可以重新计算、访问频率较高(可能是短时间内的突发访问),大小较大等等的对象。您希望尽可能长时间地将它们保留在内存中,因为它们可能会被再次重用,但您不希望因为关键对象需要而耗尽内存。这些对象适合使用弱引用。
如果这些对象不与关键资源冲突,您希望尽可能长时间地保留它们,但如果需要内存来处理关键资源,则应该将它们删除,因为需要时可以重新计算。这就是弱指针的作用。
一个例子是图片。假设您有一个包含数千张图片的网页。您需要知道要布局多少张图片,也许您需要进行数据库查询以获取列表。保存几千个项目列表所需的