这是内存泄漏还是正常行为?

时间:2011-11-14 06:42:42

标签: c# memory-leaks garbage-collection

在搜索内存泄漏时,我发现了一件奇怪的事情,我不知道它是否正常。

为了找到内存泄漏,我创建了一个带有新按钮和按钮检查的小测试应用程序:

List<WeakReference> WeakReferences = new List<WeakReference>();

private void Button_New(object sender, RoutedEventArgs e)
{
    WeakReferences.Add(new WeakReference(new ObjectUnderTest()));
    // Adding a bunch of other objects to test here
}
private void Button_Check(object sender, RoutedEventArgs e)
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();

    int AliveCounter = 0;
    foreach (var item in WeakReferences)
    {
        if (item.IsAlive)
        {
            AliveCounter++;
            Debug.WriteLine("Object " + item.Target.GetType().ToString() + " still alive!");
        }
    }
    if (AliveCounter > 0)
    {
        MessageBox.Show(AliveCounter.ToString() + " objects still alive!");
    }
    else
    {
        MessageBox.Show("No objects alive!");
    }
}

我的大多数测试对象在这种情况下都能正确收集垃圾,但仍有一些对象仍处于活动状态。

经过更多测试后,我发现这些对象确实被垃圾收集,但只有在我点击检查按钮之前切换到另一个应用程序时才会收到。

您认为,这是一种正常行为,还是内存泄漏?我必须解决这个问题?

其他信息: 目前我认为这确实是一个问题,但也许它不会出现在我们的生产代码中。

  • 只需点击一下就可以添加100个对象,在大约650个对象之后会产生内存异常,因此即使内存需要用于其他目的,GC也不会收集。
  • AddMemoryPressure不会使任何更具确定性。
  • 点击鼠标切换应用程序无济于事,只有使用ALT + TAB切换有帮助!?!
  • 有时,在我的测试应用程序中打开一个新窗口也会有所帮助。

1 个答案:

答案 0 :(得分:5)

当没有GC.Collect()参数调用GCCollectionMode时,使用GCCollectionMode.Default,在大多数版本的CLR中,GCCollectionMode.Forced与强制集合的GC.Collect(GCCollectionMode.Forced)相同发生。为确保您强制收集,请尝试拨打ObjectUnderTest

如果您仍然发现对象保持活动状态,这可能是由于您的线程与并发集合竞争(并发集合在大多数环境中是默认设置),或者您的GC.Collect(GCCollectionMode.Forced)类型可能是自我复活或有一个复杂的参考路径,这会混淆GC的第一次传递(一种不太可能的情况,但你永远不知道)?

一般情况下,GC将决定何时是收集给定对象的最佳时间,并且此行为是不确定的(除非您正在调用{{1}}或等效对象)。在某些边缘情况下,有必要影响垃圾收集器的行为,但在大多数情况下,最好让GC做它的事情而不用担心它的效率如何。这通常足够有效,并且使其有效地运作更多可能非常困难并且参与其中。