是否可以在调用它时防止垃圾收集?

时间:2009-09-24 12:30:07

标签: .net garbage-collection

我想实现一些可重用的对象池。此外,我不想让API在不需要时将对象放回池中。

我想使用垃圾收集器通知我它将删除该对象,因为它没有引用,因此我可以阻止对象被垃圾收集并将其放回池中。

5 个答案:

答案 0 :(得分:1)

我认为你不会得到一个令人满意的答案,它会神奇地返回未使用的对象,否则每个人都会这样做。 Java有一个ReferenceQueue,垃圾收集对象放在其上,但即便如此,我也不建议根据GC行为。

如果您想避免必须从池中显式释放对象,您是否考虑过使用回调/委托功能? API将接受将提供对象的委托,并且应用程序可以使用委托中的对象。完成后,保证清理。 (编辑:我的意思是保证返回游泳池)。

class Pool
{
  public delegate void UseResource(Object object);
  public void GetObject(UseResource del)
  {
    Object o = null;
    try {
      o = getFromPool();
      del(o)
    } finally {
      if (o != null) returnToPool(o);
    }
  }
}

答案 1 :(得分:0)

为什么不保留对该对象的引用,以便它不会被标记为gc?

回答您关于GC如何知道它不再使用的问题:

垃圾收集的一种方法是保持引用计数。当引用计数达到0时,不再引用该对象,并且可以是Garbage Collected。 这不是.NET实现它的方式(参见Garbage Collection),但它可能有助于更好地理解原理。

编辑: 我是如何理解的,你需要一个曾经实例化的对象池,你可以只分发和收集它们。基本上,您希望在GC之上实现内存管理。

我可以看到想要这样做的唯一原因是创建对象的新实例并使其可用(初始化)需要花费太多时间。

无论如何,您可以尝试传统的非托管方法:

Stack pool = new Stack();

// Initialize a few MyObjects
pool.Push( new MyObject() );


// Get an instance of the object from the pool
MyObject obj = (MyObject)pool.Pop();

// Use the object
obj.Foo();

// When you are finished clean up
pool.Push(obj);
obj = null;

答案 2 :(得分:0)

如果你的Pool类只是你想要的对象列表,那么它们永远不会被垃圾收集,因为你总是引用池中的对象。

答案 3 :(得分:0)

你会发现这是相对不切实际的。没有办法让GC通知你即将销毁的对象。听起来你正试图管理自己的内存空间,这不是C#面向的任务。

不可否认,您可以使用池系统和引用计数来完成它,这样您就可以知道任何人何时没有引用您的对象。但是,这似乎非常危险。

答案 4 :(得分:0)

我认为理论上可以使用C#弱引用实现回收方案。

我们的想法是为托管对象构建代理,并在客户端从池请求对象时发出代理。该池包含对真实对象的硬引用和对代理对象的弱引用。 (并且代理有一个对真实对象的硬引用。)

当应用程序删除对代理对象的引用时,它(最终)将被垃圾收集,并且(甚至更晚)池中的弱引用将被破坏。稍后,池注意到弱引用保持为null,然后可以安全地发出新代理,创建一个新的弱引用并将其发布给应用程序。

在实践中,这真是个糟糕的主意。首先,对于GC来说,弱引用可能是昂贵的,并且可能需要多个GC周期才能破坏弱引用。并添加池和代理使用的空间,以及通过代理执行操作的性能成本。最有可能的是,这些成本的总和将大大超过使用对象池回收对象的任何好处。