关于c#:如何使垃圾回收器在超出范围之前对其进行处置?

How to make Garbage collector dispose a collection before it goes out of scope?

我知道,当堆栈上不再有任何引用时,GC会清理堆上的对象。

我想知道是否有一种方法可以强制GC在此之前采取行动。 我遇到的情况是这样的。

1
2
3
4
5
6
public void A(){
    IList foo = bar();
    //does work on foo's items
    foobar();
    //more code before it goes out of scope
}

我希望我可以在调用foobar()之前释放集合使用的内存。 有没有办法做到这一点?

ps .:我知道这是不好的代码,但这是一个遗留代码,我现在无法执行任何操作。

更新:正如InBetween所指出的那样,"允许GC收集任何不可回收的对象,但是并不确定这样做。" 不幸的是,我对某些用户有内存要求,并且该应用程序必须将其内存使用率保持在一定范围内,否则我通常会让GC来工作。


I'm aware that GC will clean objects on the heap when there's no longer any reference to them on the stack.

那是不对的:

1
2
var o = new object();
return new[] { o }

好的,此方法返回后,在堆栈上对o的引用到底在哪里?

最好这样考虑:如果GC可以证明它不再可访问,则任何对象都可以进行收集。这与您所声称的完全不同。

另外,如果GC可以证明没有再次读取对给定对象的引用,那么即使存在可访问的引用,也可以收集该对象(因为从未使用过该引用,因此它与不可访问一样好)。

当GC认为这是个不错的时机时,这两种情况都由GC为您执行。它比您做的要好得多,所以让它完成工作,不要担心。在极少数情况下,您不必干预GC的工作方式。


.NET中的垃圾回收在以下三种情况下被调用:

  • 分配超出了第一代(gen 0)或大对象堆阈值,
  • 系统内存不足,
  • 通过调用GC.Collect方法
  • 根据您的"代码"判断,我可以猜到它在第一种情况下会被调用,在这种情况下(因为您仍然有对该对象的引用),我建议您将其包装到其他代码块中。例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public void A ()
    {
        DoSomethingWithTheList();
        foobar();
        //more code before it goes out of scope
    }

    private void DoSomethingWithTheList()
    {
        IList foo = bar();
        //does work on foo's items
    }

    如果这不可能,则只需尝试通过将IList对象设置为null来解除引用,然后调用具有最高生成代数的GC.Collect作为应该执行此操作的参数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public void A ()
    {
        IList foo = bar();
        //does work on foo's items
        foo = null;
        GC.Collect(2, GCCollectionMode.Forced); // force GC
        foobar();
        //more code before it goes out of scope
    }

    这假定IList foo中的对象未在其他位置引用