Ant*_* C. 2 c# lambda closures
我有一个类Test,它包含两个成员,一个(arr)占用大量内存,另一个(b)不占用:
public class Test
{
public Test() {
Arr = new int[100000000];
}
public bool B {get; private set;}
public int[] Arr {get; private set;}
}
Run Code Online (Sandbox Code Playgroud)
稍后在我的代码中,我想以这种方式存储lambda表达式:
// `test` has been declared somewhere as an instance of Test
Action lambda = () => {
if (test.B)
// Do things
}
Run Code Online (Sandbox Code Playgroud)
这个闭包的内存消耗是多少?
它会将整个Test物体保持在其环境中,还是只保留Test.b?
我应该这样做:
var tmpB = test.B;
Action lambda = () => {
if (tmpB)
// Do things
}
Run Code Online (Sandbox Code Playgroud)
闭包将存储test变量的值,变量test只是对Test内存中其他类型的对象的引用,因为它不是a struct,并且该Test对象实际上没有整数数组,它只是有一个引用存储在内存中另一个位置的大型数组.
由于您持有对该实例的引用,Test只要该闭包不符合垃圾回收条件,该对象就不符合垃圾回收的条件.如果你拉布尔值出的Test对象,然后关闭了那,当你表现,那么你就不再引用的Test对象.因此,如果没有任何东西可以访问Test实例或包含的数组,那么它就有资格进行垃圾回收.如果仍然有其他代码可以访问它,那就不是这种情况,并且没有任何好处.
它会将整个Test对象保存在其环境中,还是只保存Test.b?
好吧,它将捕获变量 test(通过创建一个单独的类来包含该变量),而后者又具有一个值,该值是对实例的引用Test.
换句话说,这样的方法:
public Action Foo()
{
Test test = new Test();
Action printB = () => Console.WriteLine(test.b);
return printB;
}
Run Code Online (Sandbox Code Playgroud)
将被转换成这样的东西:
public Action Foo()
{
CompiledGeneratedClass tmp = new CompilerGEneratedClass();
tmp.test = new Test();
Action printB = tmp.GeneratedMethod;
return printB;
}
private class CompilerGeneratedClass
{
public Test test;
public void GeneratedMethod()
{
Console.WriteLine(test.b)
}
}
Run Code Online (Sandbox Code Playgroud)
所以是的,如果你不希望委托有效地保持Test活着的实例,你应该首先提取属性的值.请注意,这有两个语义差异:
test自身的值发生变化(例如,引用不同的实例Test),您将不再在委托中看到它| 归档时间: |
|
| 查看次数: |
288 次 |
| 最近记录: |