为什么C#中的Lambda表达式会导致内存泄漏?

用户名

注意:这不仅是一些随机的无用代码,也是尝试重现Lambda表达式和C#中的内存泄漏的问题。

在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();
    }
}

DotMemory保留路径报告

EVK

如果使用某些东西(例如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,boolDelegateFuncTest

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么Objective-C中的“ try catch”会导致内存泄漏?

为什么此表达式会导致SQL错误?

在C#8中,为什么对新表达式进行类型推断会导致可为空的引用?

为什么在 lamda 表达式中读取数组会导致错误?

为什么此JavaScript会导致内存泄漏?

为什么调用堆栈数组会导致内存泄漏?

为什么使用“ new”会导致内存泄漏?

为什么重复调用FileOpenDialog会导致内存泄漏?

为什么这个函数会导致内存泄漏?

为什么基本的Swift代码会导致内存泄漏?

为什么嵌套的initializer_list会导致内存泄漏

为什么此功能会导致内存泄漏?

为什么Node.js中的全局数组会导致内存泄漏?

为什么即使删除后std :: string也会导致类中的内存泄漏

为什么类型化数组会导致JavaScript中的内存泄漏

C# - 使用 GroupBy 的 LINQ Lambda 表达式 - 为什么嵌套验证如此低效?

为什么正则表达式模式会导致 jsonschema 中的“坏字符串”错误?

为什么Lambda表达式在此Include()中无效?

订阅自己的C#事件会导致内存泄漏吗?

JavaScript-为什么包含括号会导致三元表达式错误?

为什么此Java正则表达式会导致“非法转义符”错误?

为什么我的正则表达式会导致无限循环?

为什么GNU的“-或”标志会导致我的表达式以意外的方式求值?

为什么邪恶的正则表达式会导致 ReDoS?

为什么导入正则表达式会导致回溯错误?

为什么在此表达式中用括号替换美元符号($)会导致错误?

什么是C ++中的回调地狱,为什么会泄漏内存?

为什么subdataWithRange导致任何NSThread中的内存泄漏?

c# 子列表中条件的 lambda 表达式