垃圾回收是否在 GC 之后立即运行.收集()
本文关键字:运行 收集 之后 GC 是否 | 更新日期: 2023-09-27 18:31:54
这个问题只是为了研究目的。
我读过很多关于C#的书,这个问题总是浮现在我的脑海中。据我了解,C# 是托管代码,当 CLR 决定何时运行垃圾回收时,所有垃圾回收都会发生。让我们开始吧。
假设我有一个简单的类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!";
}
}
请批准或拒绝我的假设:
- 垃圾回收没有立即在第 2 行运行是对的吗?
GC.Collect()
只是一个请求进行垃圾回收,该垃圾回收不会立即在 row2 上运行。此行可能在 x 毫秒/秒内执行。在我看来,方法System.GC.Collect();
只是对垃圾收集器说垃圾收集器应该运行垃圾收集,但真正的垃圾收集可能会在x毫秒/秒内发生
只有垃圾回收器知道何时运行垃圾回收。如果第 0 代中有可用空间,则不会在 row2: 中发生垃圾回收
row2: System.GC.Collect();
由于我们在托管环境中编程,并且只有 CLR 决定何时运行垃圾回收,因此不可能立即运行垃圾回收。垃圾回收可以在 x 毫秒/秒内运行,或者垃圾回收可能不会运行,因为第 0 代中有足够的空间在调用方法
GC.Collect()
后创建新对象。程序员可以做的只是要求CLR通过方法GC.Collect()
运行垃圾回收。
更新:
我已经阅读了这篇关于GC.Collect Method ()
的 msdn 文章..但是,我不清楚何时开始真正清除未引用的物品。MSDN 说:
气相色谱。收集方法 () 强制立即对所有 代。
但是,在评论中,我读到了这个:
使用此方法尝试回收所有无法访问的内存。它 执行所有世代的阻塞垃圾回收。
- 我对这个"使用此方法尝试"感到困惑,我认为垃圾收集可能不会发生,因为 CLR 决定有足够的空间来创建新对象。我说的对吗?
简短回答
调用 GC.Collect()
将执行完整的垃圾回收并等待它完成,但它不会等待任何挂起的终结器运行。
长答案
您的假设部分正确,因为用于运行终结器的 GC 在一个或多个后台线程中运行。(但请参阅此答案末尾的脚注。
但是,可以通过调用 GC.WaitForFullGCComplete()
来等待完整的 GC 完成,并在调用 GC.Collect()
后GC.WaitForPendingFinalizers()
:
GC.Collect();
GC.WaitForPendingFinalizers();
GC.WaitForFullGCComplete();
但是,请注意,未指定运行终结器的线程,因此无法保证此方法将终止。
请注意,您通常不应以这种方式使用 GC;我假设您有一个需要解决的特殊情况,或者您这样做是为了研究目的。
我见过的唯一有效情况是当应用程序关闭时,您希望(尝试)确保所有终结器都已运行 - 因为,例如,它们将刷新日志文件等。
如上所述,这仍然不能保证所有终结器都已运行;这只是你能做的最好的事情。
回答你的观点(5):
GC 的文档。Collect() 状态:
强制立即收集所有世代的垃圾。
因此,这将强制使用GC。
该文档还指出:
使用此方法尝试回收所有无法访问的内存。
在这里使用"try"一词仅意味着即使运行了完整的 GC,也不一定会回收所有无法访问的内存。可能出现的原因有多种,例如,终结器可能会阻塞。
脚注
.Net 4.5 允许您指定GC.Collect()
是否阻塞。
事实上,GC.Collect()
的文档指出,它对所有世代执行阻塞垃圾收集,这似乎与我上面的陈述相矛盾。然而,对于情况是否真的如此,似乎存在一些困惑。
例如,请参阅此线程。
答案是这样的:默认情况下,GC.Collect()
将等待所有世代被GCed,但它不会等待挂起的终结器,这些终结器总是在单独的线程中执行。
因此,如果您不需要等待终结器,则只需调用GC.Collect()
,而无需等待其他任何内容。
有两个 GC,从您的代码中,我相信您想知道工作站 GC。哪个通过在完整收集期间并发运行来最大程度地减少暂停?工作站 GC 使用第二个处理器并发运行集合,从而最大限度地减少延迟,同时降低吞吐量。我们应该只担心服务器 GC 没有正常工作时的 GC 行为。如果按照工作站 GC 在代码中添加 GC.collect(),则在服务器 GC 上可能毫无用处。
服务器 GC 旨在实现最大吞吐量,并以非常高的性能进行扩展。服务器上的内存碎片是一个比工作站上严重得多的问题,这使得垃圾收集成为一个有吸引力的提议。在单处理器方案中,两个收集器的工作方式相同:工作站模式,无并发收集
我对此感到困惑 使用此方法尝试,我认为垃圾收集可能不会发生,因为 CLR 决定有足够的空间来创建新对象。我说的对吗?
对于工件GC,GC。收集将尽快开始收集,您可以安全地假设它立即收集。