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

解决方法

使用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)。使用 Func 委托 (<>c.<>9__2_1) 的延迟初始化静态缓存。

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

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