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

MTR*_*MTR 2 c# garbage-collection memory-leaks

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

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

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!");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

Ada*_*lph 5

如果GC.Collect()在没有GCCollectionMode参数的情况下调用,那么GCCollectionMode.Default在大多数版本的CLR中使用的是GCCollectionMode.Forced强制集合发生的相同.要确保您强制收集,请尝试呼叫GC.Collect(GCCollectionMode.Forced).

如果你仍然发现对象保持活着,这可能是由于你的线程与并发集合竞争(并发集合在大多数环境中是默认的)或者你的ObjectUnderTest类型是自我复活或者有一个复杂的引用路径令人困惑GC的第一次通过(不太可能的情况,但你永远不知道)?

一般来说,GC将决定何时是收集给定对象的最佳时间,并且此行为是不确定的(除非您正在呼叫GC.Collect(GCCollectionMode.Forced)或等效).在某些边缘情况下,有必要影响垃圾收集器的行为,但在大多数情况下,最好让GC做它的事情而不用担心它的效率如何.这通常足够有效,并且为了使其有效地运行可能是非常困难和涉及的.

  • 如果你正在调用GC.Collect,那么它是确定性的... GCCollectionMode.Default(通过MSDN)与GCCollectionMode.Forced相同,这意味着"强制立即发生垃圾收集.".这是非常确定的. (2认同)