注意:这不仅是一些随机的无用代码,也是尝试重现Lambda表达式和C#中的内存泄漏的问题。
在C#中检查以下程序。这是一个控制台应用程序,它简单地:
我使用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();
}
}
如果使用某些东西(例如dotpeek)对代码进行反编译,则会看到编译器生成了以下内容:
public class Test {
public Test() {
if (Test.ChildGeneratedClass.DelegateInstance != null)
return;
Test.ChildGeneratedClass.DelegateInstance =
Test.ChildGeneratedClass.Instance.DelegateFunc;
}
public void WriteFirstLine() {
Console.WriteLine("Object allocated...");
}
public void WriteSecondLine() {
Console.WriteLine("Object deallocated. Press any button to exit.");
}
[CompilerGenerated]
[Serializable]
private sealed class ChildGeneratedClass {
// this is what's called Test.<c> <>9 in your snapshot
public static readonly Test.ChildGeneratedClass Instance;
// this is Test.<c> <>9__0_0
public static Func<object, bool> DelegateInstance;
static ChildGeneratedClass() {
Test.ChildGeneratedClass.Instance = new Test.ChildGeneratedClass();
}
internal bool DelegateFunc(object _) {
return true;
}
}
}
因此,它创建了子类,将您的函数作为该类的实例方法,在静态字段中创建了该类的单例实例,最后使用引用方法创建了静态字段。因此,GC不能收集编译器生成的那些静态成员也就不足为奇了。当然,不会为您创建的每个对象创建一次这些对象,因此我不能真正称其为“泄漏”。Func<object,bool
DelegateFunc
Test
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句