在搜索内存泄漏时,我发现了一件奇怪的事情,我不知道它是否正常。
为了找到内存泄漏,我创建了一个带有新按钮和按钮检查的小测试应用程序:
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!");
}
}
我的大多数测试对象在这种情况下都能正确收集垃圾,但仍有一些对象仍处于活动状态。
经过更多测试后,我发现这些对象确实被垃圾收集,但只有在我点击检查按钮之前切换到另一个应用程序时才会收到。
您认为,这是一种正常行为,还是内存泄漏?我必须解决这个问题?
其他信息: 目前我认为这确实是一个问题,但也许它不会出现在我们的生产代码中。
答案 0 :(得分:5)
当没有GC.Collect()
参数调用GCCollectionMode
时,使用GCCollectionMode.Default
,在大多数版本的CLR中,GCCollectionMode.Forced
与强制集合的GC.Collect(GCCollectionMode.Forced)
相同发生。为确保您强制收集,请尝试拨打ObjectUnderTest
。
如果您仍然发现对象保持活动状态,这可能是由于您的线程与并发集合竞争(并发集合在大多数环境中是默认设置),或者您的GC.Collect(GCCollectionMode.Forced)
类型可能是自我复活或有一个复杂的参考路径,这会混淆GC的第一次传递(一种不太可能的情况,但你永远不知道)?
一般情况下,GC将决定何时是收集给定对象的最佳时间,并且此行为是不确定的(除非您正在调用{{1}}或等效对象)。在某些边缘情况下,有必要影响垃圾收集器的行为,但在大多数情况下,最好让GC做它的事情而不用担心它的效率如何。这通常足够有效,并且使其有效地运作更多可能非常困难并且参与其中。