【发布时间】:2018-11-25 01:44:16
【问题描述】:
让我们看下面的例子(请注意,成员之所以是静态的,纯粹是因为我希望它尽可能短且可运行):
public class Program
{
private static readonly ReaderWriterLock Lock = new ReaderWriterLock();
public static void SafeRead(Action action)
{
Lock.AcquireReaderLock(1000);
try
{
action();
}
finally
{
Lock.ReleaseReaderLock();
}
}
public static void Main(string[] args)
{
SafeRead(() => Console.WriteLine(args));
}
}
在 ILSpy 中查看后,我可以看到为 lambda 创建了一个内部类“c__DisplayClass2_0”。该类包含存储在公共字段中的方法和对局部变量“args”的引用,如下所示:
.class nested private auto ansi sealed beforefieldinit '<>c__DisplayClass2_0'
extends [mscorlib]System.Object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Fields
.field public string[] args
// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{} // end of method '<>c__DisplayClass2_0'::.ctor
.method assembly hidebysig
instance void '<Main>b__0' () cil managed
{} // end of method '<>c__DisplayClass2_0'::'<Main>b__0'
} // end of class <>c__DisplayClass2_0
我知道如果 lambda 超出 args 局部变量和 Main 方法本身的生命周期,则需要类和字段。但是,如果我可以确保像我的示例中那样在 Main 方法中同步调用 lambda 怎么办?可能在 Program 类中创建一个内部字段和一个方法就足够了,而不是创建一个额外的类。我知道 Program 类的大小会因这个内部字段而增加,但是如果非常频繁地调用任何包含此类匿名委托的方法,那么每次调用都会创建一个额外的类,如果我更喜欢性能,这在我看来情况更糟内存消耗过多..有没有办法指示编译器不要在我的场景中创建内部类?还是我错过了什么重要的东西?
【问题讨论】:
-
异常这个实现细节不太可能成为实际程序中任何性能问题的根本原因。它是编译器的一个实现细节,它会出于各种原因生成类。
-
另外,请记住,一般而言,任何方法都可能被多个线程同时调用。使用您的“只保留一个本地字段”方法,当第二个调用者
Main为args传递一个不同的值而第一个调用者的调用仍在运行并且尚未使用它时会发生什么? -
但我敢打赌,当它成为性能瓶颈且未达到性能目标时,您会将注意力集中在此处。这是否意味着您现在从不使用
foreach,或者您仍然在最常见的使用场景中使用它? -
这个额外类的全部原因是将所有封闭变量捆绑到一个持久对象中。如果您不使用闭包,则没有理由使用匿名委托(即您可以直接引用类方法),并且您将不再有“隐藏”类的扩散。总而言之,这可能是毫无意义的微优化的一课。
-
我叫恶作剧,你有 gc 或性能问题吗?