首页 > 解决方案 > 在 List.ForEach 中声明 Func<> 会导致内存泄漏并增加进程内存吗?

问题描述

我知道我不应该在Func<>内部声明foreach,但我想知道这段 C# 代码是否会增加进程内存并导致内存泄漏?

class Foo {
    int[] FooA = { 1, 2, 3, 4 };
    string result = "";
    void myMethod() {
        FooA.ToList().ForEach(a => {
            Func<int, string> myFunc = myFuncVar => $"Value: {myFuncVar}\n";
            result += myFunc(a);
        });
        MessageBox.Show(result);
    }
}

标签: c#memory-leaksfunc

解决方案


使用Sharplab之类的反汇编工具很有帮助;

// trim
internal class Foo
{
    [Serializable]
    [CompilerGenerated]
    private sealed class <>c
    {
        public static readonly <>c <>9 = new <>c();

        public static Func<int, string> <>9__2_1;

        internal string <myMethod>b__2_1(int myFuncVar)
        {
            return string.Format("Value: {0}\n", myFuncVar);
        }
    }

    private int[] FooA;

    private string result;

    private void myMethod()
    {
        Enumerable.ToList(FooA).ForEach(new Action<int>(<myMethod>b__2_0));
    }

    public Foo()
    {
        int[] array = new int[4];
        RuntimeHelpers.InitializeArray(array, (RuntimeFieldHandle)/*OpCode not supported: LdMemberToken*/);
        FooA = array;
        result = "";
        base..ctor();
    }

    [CompilerGenerated]
    private void <myMethod>b__2_0(int a)
    {
        Func<int, string> func = <>c.<>9__2_1 ?? (<>c.<>9__2_1 = new Func<int, string>(<>c.<>9.<myMethod>b__2_1));
        result += func(a);
    }
}
// trim

您可以看到您的 lambda ( myFuncVar => $"Value: {myFuncVar}\n";) 已被提升为<myMethod>b__2_1单例实例 ( ) 上的方法 ( <>c.<>9)。<>c.<>9__2_1使用 Func 委托 ( )的延迟初始化静态缓存。

所以不,至少在这种情况下,这里实际上没有每次迭代分配。

编译器可以证明您的 lambda 不需要对局部变量的引用,也不需要任何其他实例字段。即使您分配给该 lambda 的变量具有本地范围和生命周期,也可以将 lambda 本身提升为静态生命周期。类似于将字符串文字分配给变量的方式,但字符串对象具有静态生命周期。


推荐阅读