【问题标题】:Why doesn't .NET have a SoftReference as well as a WeakReference, like Java?为什么 .NET 没有像 Java 那样的 SoftReference 和 WeakReference?
【发布时间】:2010-09-24 09:20:36
【问题描述】:

我真的很喜欢 WeakReference 的。但我希望有一种方法可以告诉 CLR 你认为引用有多弱(例如,在 1 到 5 的范围内)。那太好了。

Java 有 SoftReference、WeakReference,我相信还有第三种类型,称为“幻像引用”。那是 3 个级别,GC 在决定该对象是否获得印章时具有不同的行为算法。

我正在考虑对 .NET 的 WeakReference 进行子类化(幸运的是,有点奇怪的是它没有被密封)来创建一个基于过期计时器或其他东西的伪 SoftReference。

【问题讨论】:

  • 也许如果你解释你要解决什么问题,你可能会得到一些好的解决方案。通常在这种粒度级别上工作并不是一个好主意,某种形式的过期缓存更合适,但这完全取决于问题。

标签: c# weak-references soft-references


【解决方案1】:

我认为 NET 没有软引用的根本原因是它可以依赖于具有虚拟内存的操作系统。 Java 进程必须指定它的最大 OS 内存(例如使用 -Xmx128M),并且它永远不会占用比这更多的 OS 内存。而 NET 进程不断占用它需要的操作系统内存,当 RAM 用完时,操作系统会提供磁盘支持的虚拟内存。如果 NET 允许软引用,那么 NET 运行时将不知道何时释放它们,除非它深入操作系统以查看其内存是否实际在磁盘上分页(讨厌的 OS/CLR 依赖项),或者它请求运行时指定最大进程内存占用(例如,相当于-Xmx)。我猜微软不想将-Xmx 添加到 NET,因为他们认为操作系统应该决定每个进程获得多少 RAM(通过选择哪些虚拟内存页面保存在 RAM 或磁盘上),而不是进程本身。

【讨论】:

  • 但也许对于 .Net Compact 这样的东西可能有用。
【解决方案2】:

Java SoftReferences 用于创建内存敏感缓存(它们没有其他用途)。

从 .NET 4 开始,.NET 有一个 System.Runtime.Caching.MemoryCache 类,它可能会满足任何此类需求。

【讨论】:

  • 这是一个非常好的指针,应该在答案的顶部。
  • 这是一个很好的补充,但我想知道它的灵活性。我通常赞成暴露机制而不是经销商黑匣子。它们往往在现实世界的生产中更有用。 (Granted GC 本身通常是一个密封的黑匣子,但至少 Java 允许您更换整个收集器,如果您真的愿意的话。)
  • 我同意,一般来说 - 我更喜欢暴露机制而不是黑盒,这是我更喜欢 Java 而不是 C# 的原因之一。但另一方面,每个新的 java 垃圾收集器都需要自己的 SoftReferences 实现,这可能很容易比您当前的 GC 更不适合您的目的。改变 GC 并不是一件容易的事(至少在低暂停/低延迟的环境中)。
【解决方案3】:

拥有不同程度的弱点(优先级)听起来很好的 WeakReference,但也可能使 GC 的工作更难,而不是更容易。 (我不知道 GC 内部结构,但是)我会假设为 WeakReference 对象保留了某种额外的访问统计信息,以便 GC 可以有效地清理它们(例如,它可能会删除最少使用的项目第一的)。

增加的复杂性很可能不会使任何事情变得更有效,因为最有效的方法是首先摆脱不经常使用的 WeakReferences。如果你可以指定一个优先级,你会怎么做?这听起来像是过早的优化:程序员大部分时间并不真正知道并且在猜测;结果是较慢的 GC 收集周期,很可能回收了错误的对象。

这引出了一个问题,如果您关心被回收的 WeakReference.Target 对象,那么 WeakReference 真的很好用吗?

它就像一个缓存。您将内容塞入缓存并要求缓存在 x 分钟后使其陈旧,但大多数缓存根本不保证将其保留。它只是保证如果确实如此,它将根据请求的策略将其过期。

【讨论】:

  • 不同之处在于,使用 SoftReference 缓存可以让您在有足够内存的情况下保存它们,但如果没有,则将它们丢弃。它是一个比缓存超时更有效的解决方案。
  • @user430788 我想你错过了我关于缓存的评论。缓存已经可以使用 Wea​​kReference,但陈旧性也可能适用于缓​​存的项目。从缓存消费者的角度来看,缓存通常不能保证项目会保留在缓存中。开发人员已经在抱怨 GC,所以 C# 团队可能觉得添加新级别的弱引用(软、幻象)还不够。与往常一样,Eric Lippert 的 blogs.msdn.com/b/ericlippert/archive/2003/10/28/… 是深入了解 C# 功能的好读物。
  • 罗伯特,恐怕你根本不了解我。不,缓存不能保证东西留在缓存中。这才是重点。但是仅基于时间的缓存并不能很好地确定内存中应该和不应该是什么。它无缘无故地冲洗东西。基于内存需求的缓存在保存数据方面要好得多,除非它真的需要被删除。您可以自己实现 LRU 缓存,但这需要向您的应用程序添加伪内存管理代码。让已经在管理内存的 GC 管理缓存会更有效。
【解决方案4】:

我对为什么不存在的猜测很简单。大多数人,我认为,将其称为一种美德,即只有一种类型的参考,而不是四种。

【讨论】:

  • 实际上 SoftReferences 非常有用,因为它们允许 gc 感知内存敏感缓存。大多数真正了解自己擅长什么的人都希望拥有它们。在 Java 代码中,我使用 SoftReference 比 WeakReference 更频繁
【解决方案5】:

也许 ASP.NET 缓存类 (System.Web.Caching.Cache) 可能有助于实现您想要的?如果内存不足,它会自动删除对象:

这是一篇介绍如何在 Windows 窗体应用程序中使用 Cache 类的文章。

引用自:Equivalent to SoftReference in .net?

【讨论】:

    【解决方案6】:

    不要忘记您也有自己的标准参考资料(您每天使用的参考资料)。这为您提供了更高的级别。

    WeakReferences 应该在你真的不关心对象是否消失时使用,而 SoftReferences 只应该在你使用普通引用时才应该使用,但是你宁愿你的对象被清除以便你用完记忆。我不确定具体细节,但我怀疑 GC 在确定哪些对象处于活动状态时通常会跟踪 SoftReferences 而不是 WeakReferences,但当内存不足时也会跳过 SoftReferences。

    我的猜测是 .Net 设计者认为这种差异让大多数人感到困惑,或者 SoftReferences 增加了比他们真正想要的复杂性更高的复杂性,因此决定将它们排除在外。

    附带说明一下,AFAIK PhantomReferences 主要是为虚拟机内部使用而设计的,而不是供实际客户端使用的。

    【讨论】:

    • 请参阅上面的我的 cmets,了解 SoftReference 的用途以及它们如何让您更有效地编码。幻影参考适用于真正需要进行某种事后清理的任何人。
    【解决方案7】:

    也许应该有一个属性,您可以在其中指定对象 >= 在收集之前的哪个世代。所以如果你指定 1 那么它是最弱的参考。但是,如果您指定 3,那么它需要在之前的至少 3 次收集中存活下来,然后才能考虑将其用于收集本身。

    我认为轨道恢复标志对此没有好处,因为到那时对象已经完成了?虽然可能是错的......

    (PS:我是 OP,刚刚注册。PITA 不会从“未注册”帐户继承您的历史记录。)

    【讨论】:

      【解决方案8】:

      寻找传递给构造函数的“trackResurrection”选项?

      GC 类也提供了一些帮助。

      【讨论】:

        【解决方案9】:

        不知道为什么 .NET 没有软引用。 但是在 Java 软引用中,恕我直言,过度使用。原因是至少在应用程序服务器中,您希望能够影响每个应用程序的 Softreferenzen 存活时间。目前这在 Java 中是不可能的。

        【讨论】:

        猜你喜欢
        • 2010-09-22
        • 2011-03-20
        • 1970-01-01
        • 2011-09-25
        • 2011-02-06
        • 2011-11-01
        • 2010-10-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多