注意:这不是一些随意无用的代码,而是尝试在C#中重现lambda表达式和内存泄漏问题的代码。
检查以下C#程序。这是一个控制台应用程序,简单地执行以下操作:
1.创建一个Test类型的新对象 2.向控制台写入对象已创建的消息 3.调用垃圾回收 4.等待任何用户输入 5.关闭
我使用JetBrains DotMemory运行此程序,并且拍摄了两个内存快照:一个是在对象初始化之后,另一个是在其被收集之后。我比较这些快照并得到我期望的结果:一个Test类型的死对象。
但是,这里有个问题:然后我在对象的构造函数中创建了一个本地lambda表达式,并且没有在任何地方使用它。它只是一个本地构造变量。我在DotMemory中运行相同的过程,突然间,我得到了一个Test+<>类型的对象,它可以在垃圾回收之后继续存在。
从DotMemory附带的保留路径报告中可以看出:lambda表达式具有指向Test+<>对象的指针,这是预期的。但是谁有指向lambda表达式的指针,为什么它会保存在内存中?
此外,这个Test+<>对象——我认为它只是一个临时对象,用于保存lambda方法,并与原始Test对象无关,我对吗?
检查以下C#程序。这是一个控制台应用程序,简单地执行以下操作:
1.创建一个Test类型的新对象 2.向控制台写入对象已创建的消息 3.调用垃圾回收 4.等待任何用户输入 5.关闭
我使用JetBrains DotMemory运行此程序,并且拍摄了两个内存快照:一个是在对象初始化之后,另一个是在其被收集之后。我比较这些快照并得到我期望的结果:一个Test类型的死对象。
但是,这里有个问题:然后我在对象的构造函数中创建了一个本地lambda表达式,并且没有在任何地方使用它。它只是一个本地构造变量。我在DotMemory中运行相同的过程,突然间,我得到了一个Test+<>类型的对象,它可以在垃圾回收之后继续存在。
从DotMemory附带的保留路径报告中可以看出:lambda表达式具有指向Test+<>对象的指针,这是预期的。但是谁有指向lambda表达式的指针,为什么它会保存在内存中?
此外,这个Test+<>对象——我认为它只是一个临时对象,用于保存lambda方法,并与原始Test对象无关,我对吗?
public class Test
{
public Test()
{
// this line causes a leak
Func<object, bool> t = _ => true;
}
public void WriteFirstLine()
{
Console.WriteLine("Object allocated...");
}
public void WriteSecondLine()
{
Console.WriteLine("Object deallocated. Press any button to exit.");
}
}
class Program
{
static void Main(string[] args)
{
var t = new Test();
t.WriteFirstLine();
Console.ReadLine();
t.WriteSecondLine();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.ReadLine();
}
}
GC.Collect()
实际收集它呢?在调用GC.Collect()
之前尝试将t
设置为null,看看会发生什么。 - Zohar Peled