我开始学习 GC 和 finalization,我遇到了一个非常简单的示例,其中应用程序的行为对我来说非常出乎意料。
(注意:我知道终结器只能用于非托管资源并使用一次性模式,我只是想了解这里发生了什么。)
这是一个简单的控制台应用程序,可生成“锯齿”模式的内存。内存上升到 90MB 左右,然后进行 GC,下降并再次开始上升,永远不会超过 90MB。
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 100000; i++)
{
MemoryWaster mw = new MemoryWaster(i);
Thread.Sleep(250);
}
}
}
public class MemoryWaster
{
long l = 0;
long[] array = new long[1000000];
public MemoryWaster(long l)
{
this.l = l;
}
//~MemoryWaster()
//{
// Console.WriteLine("Finalizer called.");
//}
}
如果我用终结器删除注释,行为会非常不同——应用程序在开始时执行一到两次 GC,但随后内存以线性方式增加,直到它使用超过 1GB 的内存(此时我终止应用程序)
根据我的阅读,这是因为 GC 没有释放项目,而是将对象移动到终结队列。GC 启动一个线程来执行终结器方法,然后等待另一个 GC 移除终结对象。当终结器方法运行时间很长时,这可能是一个问题,但这里不是这种情况。
如果我每隔几次迭代手动触发一次运行 GC.Collect(),则应用程序会按预期运行,并且我会看到内存的锯齿模式被释放。
我的问题是 - 为什么应用程序使用的大量内存不会自动触发 GC?在包含终结器的示例中,GC 会在第一次之后再次运行吗?