GC.Collect() 之后是否立即进行垃圾回收 运行?

Does garbage collection run immediately after GC.Collect()?

提问仅供研究。

我看了很多关于C#的书,这个问题总是浮现在我的脑海中。据我了解,C# 是托管代码,当 CLR 决定何时 运行 垃圾回收时,所有垃圾回收都会发生。开始吧。

假设我有简单的 class Student:

public class Student
{
    public int IdStudent { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
}
class Program
{
      static void Main(string[] args)
      {
This is row1:    Person person = new Person() {IdPerson=1, Name="Bill", SurName="Collins"};
This is row2:    System.GC.Collect();
This is row3:    string str="Hello World!";
    }        
}

请批准或拒绝我的假设:

  1. 垃圾收集不是 运行 立即在 row2,我说得对吗?
  2. GC.Collect() 只是一个 请求 进行垃圾收集,不会 运行 立即在第 2 行。此行 可能在 x milliseconds/seconds 中执行 。 在我看来,方法 System.GC.Collect(); 只是告诉垃圾收集器垃圾收集器应该 运行 垃圾收集,但是 真正的垃圾收集可能发生在 x milliseconds/seconds

  3. 只有垃圾收集器知道何时进行垃圾收集运行。并且如果第 0 代中有空闲 space,那么垃圾收集将不会发生在 row2: row2: System.GC.Collect();

  4. 不可能立即 运行 垃圾回收,因为我们在托管环境中编程,只有 CLR 决定何时 运行 垃圾回收。 垃圾收集可以是 运行 in x milliseconds/seconds 或者垃圾收集 可能不是 运行 因为有足够的 space in第 0 代在调用方法 GC.Collect() 后创建新对象。程序员可以做的只是要求 CLR 通过 GC.Collect().

  5. 方法进行 运行 垃圾收集

更新:

我读过 this msdn article about GC.Collect Method ().。但是,我不清楚何时开始真正清除未引用的对象。 MSDN 说:

GC.Collect Method () forces an immediate garbage collection of all generations.

但是,在备注中,我读到了这个:

Use this method to try to reclaim all memory that is inaccessible. It performs a blocking garbage collection of all generations.

  1. 我对此感到困惑 "Use this method to TRY" 我认为垃圾回收 可能不会发生 因为 CLR 决定有足够的 space 来创建新对象。我说得对吗?

简答

调用 GC.Collect() 将执行完整的垃圾收集并等待它完成,但它不会等待任何挂起的终结器到 运行。

长答案

您的假设部分正确,因为 运行ning 终结器的 GC 在一个或多个后台线程中 运行。 (但请参阅此答案末尾的脚注。)

但是, 可以在调用 GC.Collect():

之后调用 GC.WaitForFullGCComplete() and GC.WaitForPendingFinalizers() 等待完整的 GC 完成
GC.Collect();
GC.WaitForPendingFinalizers();
GC.WaitForFullGCComplete();

但是,请注意 终结器所在的线程 运行 未指定,因此无法保证此方法会终止。

请注意,您通常不应以这种方式使用 GC;我假设您有一个特殊情况需要解决,或者您这样做是为了研究目的。

我见过的唯一有效的情况是当应用程序正在关闭时,并且您想(尝试)确保所有终结器都已 运行 - 因为,例如,它们将刷新日志文件等

如上所述,这仍然不能保证所有终结器都已 运行;这只是你能做的最好的。

针对您的观点 (5) 的回答:

GC.Collect() 的文档指出:

强制立即对所有代进行垃圾回收。

所以这强制GC。

文档还指出:

使用此方法尝试回收所有不可访问的内存。

这里使用"try"这个词仅仅意味着即使是full GC运行,也不一定会回收所有无法访问的内存。发生的原因有多种,例如,终结器可能会阻塞。

脚注

.Net 4.5 allows you to specify whether GC.Collect() is blocking or not.

事实上,GC.Collect() 的文档指出 它执行所有代的阻塞垃圾收集,这似乎与我上面的陈述相矛盾。但是,对于是否真的如此,似乎有些困惑。

参见示例 this thread

答案是这样的:GC.Collect()默认等待所有代被GC,但它不会等待挂起的终结器,它们总是在一个单独的线程。

因此,如果你不需要等待终结器,你只需要调用 GC.Collect() 而你不需要等待任何其他东西。

有两个 GC,从您的代码来看,我相信您想了解工作站 GC。 运行 在完全收集期间,哪个并发最大限度地减少了暂停?工作站 GC 使用第二个处理器并发 运行 收集,从而在降低吞吐量的同时最大限度地减少延迟。如果服务器 GC 没有正常工作,我们应该只担心 GC 行为。如果您按照工作站 GC 在代码中添加 GC.collect(),那在服务器 GC 上可能没用。

服务器 GC 旨在实现最大吞吐量,并以非常高的性能进行扩展。服务器上的内存碎片比工作站上的问题严重得多,这使得垃圾收集成为一个有吸引力的提议。在单处理器场景下,两个收集器的工作方式相同:工作站模式,没有并发收集

I am confused by this Use this method to TRY and I think that garbage collection may not occur cause CLR decides that there is enough space to create new objects. Am I right?

对于工作站 GC,GC.Collect 将尽快开始收集,您可以安全地假设它会立即收集。