弱引用的好处

75

有人能解释 C# 中不同类型引用的主要优点吗?

  • 弱引用
  • 软引用
  • 幻影引用
  • 强引用。

我们有一个消耗大量内存的应用程序,我们正在尝试确定这是否是一个需要关注的领域。


您的应用程序是否专门使用了 System.WeakReference 类? - MusiGenesis
3个回答

61

Soft和phantom references出自Java,我相信。 在C#中,长弱引用(向WeakReference构造函数传递true)可能被认为类似于Java的PhantomReference。 如果有类似于SoftReference的C#内容,我不知道它是什么。

弱引用并不延长对象的生命周期,因此一旦所有强引用超出范围,它就可以进行垃圾回收。 它们可用于持有大型且初始化成本高昂的对象,但如果它们未被积极使用,则应该可供垃圾回收。

是否使用弱引用有助于减少应用程序的内存消耗将完全取决于应用程序的具体情况。 例如,如果您拥有适度数量的缓存对象,并且这些对象将来可能或可能不会被重用,弱引用可以帮助提高缓存的内存消耗。 但是,如果应用程序正在处理大量小对象,弱引用会使问题变得更糟,因为引用对象将占用同样多或更多的内存。


3
另请参阅:弱引用 (MSDN) - George Duckett

35

MSDN提供了关于弱引用的良好解释。其关键引述在底部,其中指出:

避免将弱引用用作自动解决内存管理问题的方案。 相反,开发一个有效的缓存策略来处理应用程序对象。

每次我在现实中看到WeakReference时,它都被用作自动解决内存管理问题的方案。 对于您的应用程序问题,可能有更好的解决方案。


2
我发现这个引用有些令人困惑,因为似乎每次使用弱引用都可以由应用程序处理。在文档中提供的示例中,比如一个 TreeView,应用程序可以监控用户是否在一段时间内使用了 TreeView,如果没有,则将 TreeView 设置为 null,让垃圾收集器来处理。这样能够达到相同的效果,但是由应用程序来处理。 - Carl G
2
@DGGenuine:就我个人而言,我完全看不出弱引用有什么用处。在我继承的一些项目中遇到过它们,在每种情况下我都必须将其完全删除,因为最初的开发人员并不理解它们的作用和意义。 - MusiGenesis
10
“我根本看不出弱引用有什么用处。” 直到在启用垃圾回收的运行时中出现内存泄漏,因为代码中某个地方有一个对保持所有树引用的树节点的引用,因此该对象无法进行垃圾回收,尽管它已经不再被使用。 弱引用被用作弱引用(双关语意)。"如果对象仍在使用,则我希望能够对其进行操作,但如果不再使用,则绝不要让我保持其活动状态。" 这是代码卫生,确定对象的所有权或非所有权。 - paercebal
9
@paercebal似乎在说弱引用的一个有效用途是用作代码中其他地方的错误修复/变通方法。我猜你可以这样论述。 - MusiGenesis
6
事件应该始终使用弱引用,但不幸的是它们默认情况下并不是这样。微软提供了一个处理事件使用弱引用的类,但不幸的是其语法令人难以忍受。但是幸运的是,有一个事件库为弱事件提供了简单的语法,同时还改进了事件(例如,可以简单地将多个发布连接到同一个事件,消除不必要的耦合等)。 - BlueRaja - Danny Pflughoeft

6

Android开发教程中,通过弱引用的实际案例很好地解释了这个问题。

视图上有一张图片(Bitmap)和一个图片容器(ImageView)。如果从内存之外的位置(例如磁盘、网络)加载图片,则可能会锁定UI线程和屏幕。为了避免这种情况,可以使用异步任务。

问题出现在异步任务完成时。此时,图片容器可能已经没有用处了(屏幕已经改变或者Android在滚动后卸载了不可见的部分)。弱引用可以帮助解决这个问题,并且ImageView将被垃圾回收。

class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
    private final WeakReference<ImageView> imageViewReference;

    public BitmapWorkerTask(ImageView imageView) {
        imageViewReference = new WeakReference<ImageView>(imageView);
    }
    // Method for getting bitmap is removed for code clearness

    // Once complete, see if ImageView is still around and set bitmap.
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (imageViewReference != null && bitmap != null) {
            final ImageView imageView = imageViewReference.get();
            if (imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}

附注:示例是用Java编写的,但C#开发人员也可以理解。
来源:http://developersdev.blogspot.ru/2014/01/weakreference-example.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接