我一直在阅读 Jeffrey Richter 的好书“CLR via C#”中的垃圾收集章节。在那里,他通过引用从 JIT 编译器发出的 native 代码的反汇编列表,说明了 GC 在概念上如何工作(如何标记根)的示例。从那个例子中,我想到在范围内嵌套引用类型似乎对加速嵌套变量的垃圾收集有零影响。我想知道我是否理解正确。无论如何,请考虑这两个版本的代码:
A) 在内部范围内嵌套引用类型变量 (y):
namespace scope
{
class A { public void foo() { } }
class Program
{
static void Main(string[] args)
{
A x = new A();
x.foo();
{
A y = new A();
y.foo();
}
}
}
}
B) 同上,只是 x 和 y 在同一范围内。
namespace scope
{
class A { public void foo() { } }
class Program
{
static void Main(string[] args)
{
A x = new A();
x.foo();
A y = new A();
y.foo();
}
}
}
出于好奇,我检查了两个版本生成的 IL 代码,它们是一样的!
Q1:所以,这似乎暗示,范围界定确实不会以任何方式加速垃圾收集。这样对吗? (注意:我知道“using”语句 - 但我只对上面 2 个示例中所示的“普通旧范围”的 GC 行为感到好奇。)
问题 2:如果问题 1 的答案是“正确”,那么我对“对象生命周期不是由作用域决定”的情况如何可能发生感到非常困惑,如下所述: http://www.curly-brace.com/favorite.html
最佳答案
垃圾收集部分取决于您是否在调试器中运行。我假设我们不是。
它实际上可能比您想象的更具侵略性。例如:
object o = new object();
Console.WriteLine(o);
Console.WriteLine("hi");
o = new object();
对象可以在第二行之后立即被垃圾回收——即在变量 o
退出作用域之前很久。如果没有最后一行,这也是正确的。
换句话说,作用域不会加速垃圾收集 - 因为 GC 已经比您想象的更聪明。
事实上,垃圾收集器可以甚至更激进。考虑这段代码:
Foo f = new Foo();
f.SomeMethod();
Console.WriteLine("Hello");
Foo 看起来像这样:
public class Foo
{
int x = 10;
public void SomeMethod()
{
Console.WriteLine(x);
for (int i = 0; i < 100; i++)
{
Console.WriteLine("Hello");
Thread.Sleep(100);
}
}
}
理论上,垃圾收集器可以在 SomeMethod
运行时收集 Foo
对象,只要它越过第一行,其中它实际上是从 x
读取的。如果 Foo
有终结器,您可以让终结器在一个线程中运行,而 SomeMethod
在另一个线程中运行。可怕的东西。
关于c# - 内部范围内嵌套引用类型对象对垃圾回收没有影响 : True or False?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3101530/