【问题标题】:C# - Get number of references to objectC# - 获取对对象的引用数
【发布时间】:2010-12-13 18:32:09
【问题描述】:

我正在尝试为我正在编写的小游戏编写一个简单的资源管理器。此资源管理器需要执行的任务之一是卸载未使用的资源。我可以考虑通过两种方式做到这一点:

  • 当对象不再需要 引用资源,它必须 调用资源管理器的方法 表示它不再使用它; 或

  • 当对象不再需要 引用资源,它只是 将其设置为空。那么当 资源管理器被要求卸载 未使用的资源,它得到 引用计数(通过反射?) 每个资源。如果引用计数 是一(资源管理器将 有对资源的引用), 卸载资源。

有没有办法在 C# 中实现第二个解决方案? 谢谢。

【问题讨论】:

  • 您的资源管理器会做哪些垃圾收集器不会做的事情?
  • @CannibalSmith - 通常,允许多位代码重用资源(本质上是缓存)
  • 它用于加载图片,确保一次只加载一张图片(无论请求多少,内存中只能有一个版本)。

标签: c# reflection resources reference resourcemanager


【解决方案1】:

我们已经在 .NET 中有一个资源管理器,称为垃圾收集器。因此,一种非常有效的方法是将引用设置为 null 并且什么都不做。

更直接的答案:不,没有办法获得对象的引用。

您可能想研究WeakReference class 或使用缓存系统。

【讨论】:

    【解决方案2】:

    确保资源管理器对您的资源使用WeakReferences。这样,当没有其他人引用资源时,他们将有资格进行垃圾回收。

    【讨论】:

      【解决方案3】:

      在我看来,您可以使用资源管理器中的WeakReference。 GC 将完成其余的工作。您需要进行一些铸造,但它会很简单,并且会起作用。

      class Manager {
          Dictionary<string, WeakReference> refs =
              new Dictionary<string, WeakReference>();
          public object this[string key] {
              get {
                  WeakReference wr;
                  if (refs.TryGetValue(key, out wr)) {
                      if(wr.IsAlive) return wr.Target;
                      refs.Remove(key);
                  }
                  return null;
              }
              set {
                  refs[key] = new WeakReference(value);
              }
          }
      }
      static void Main() {
          Manager mgr = new Manager();
          var obj = new byte[1024];
          mgr["abc"] = obj;
      
          GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
          Console.WriteLine(mgr["abc"] != null); // true (still ref'd by "obj")
      
          obj = null;
          GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
          Console.WriteLine(mgr["abc"] != null); // false (no remaining refs)
      }
      

      【讨论】:

      • 我会这样做 :) 但有一件事:我可能是错的,但我认为您可能必须从字典中获取正确的引用并在返回之前检查它是否为空。如果您执行“if(wr.IsAlive) return wr.Target”,则您永远不会采用强引用,因此 IsAlive 可能会返回 true,但是当您返回值时,wr.Target 可能已被收集。这里有一个替代代码示例:msdn.microsoft.com/en-us/library/system.weakreference.aspx
      • object 足够强大,可以防止收集;要么是null,要么是强大的。调用者必须将其转换为 typed 引用,但这是一个不同的问题...
      • .NET 4.5 有一个通用版本的 WeakReference,看看这个philosophicalgeek.com/2014/08/14/…
      • 不是缓存的全部意义在于能够重用资源,即使它们暂时不需要?如果缓存被 GC 清理了,那么缓存除了模糊代码还有其他作用吗?它不会只是假装它做的事情与 GC 不同。
      • @AdasLesniak 我不是询问者,但一个用例是将缓存保持在一定大小。检查对象当前是否被使用 - 这样做是为了不会在您的 UI 中造成错误,然后将其删除或保留。是的,基本上这是您自己的缓存的“GC”。
      【解决方案4】:

      正如其他用户已经告知的那样,您想要实现的目标已经由 GC 完成,并且可以使用 WeakReference 进行微调。

      这意味着在 .NET、java 等托管环境中,这不是问题。

      由于底层框架架构将您与内存管理隔离开来,如果您仍然需要那种功能,我强烈建议您审查自己的代码架构,因为这意味着您正在做一些不好的事情- 练习内存管理

      【讨论】:

        【解决方案5】:

        几件事。首先,对象不被引用计数;引用计数方案存在循环引用问题,即两个对象相互引用但无法访问,从而导致泄漏。 .NET 使用不使用引用计数的标记和清除方法。

        其次,虽然使用弱引用的建议并不可怕,但它也不是灌篮。出于性能原因,您正在构建缓存。 (我假设您对应用程序性能特征的仔细、经验和现实的研究已经令人信服地证明了缓存策略对于实现可接受的性能是必要的;如果不是这样,那么您就过早地做出这些决定。)缓存必须有关于何时释放资源的 POLICY,否则就是内存泄漏。

        您怎么知道 GC 政策和您的政策是等效政策? GC 的设计并未考虑到您的特定性能需求。也就是说,它旨在释放真正垃圾的资源,而不是实现您心中的任何特定性能目标。通过将决定权委托给 GC,您放弃了根据性能需求调整缓存策略的能力。

        【讨论】:

          猜你喜欢
          • 2012-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多