Kev*_*vin 8 c# garbage-collection
所以我知道这里的基础知识 - 当一个对象不再可以被根访问时(即来自堆栈帧中的局部变量或静态引用的强引用),该对象有资格进行垃圾回收.
我的问题是这个潜在的优化,即使从局部变量引用一个对象,它也可能在函数中不再引用该变量的任何点进行垃圾收集.首先 - 似乎现有的C#实现不会这样做 - 2.0和4.0似乎都会保持本地引用"直播",直到堆栈帧被销毁.但是 - 如果在CLR的更高版本中优化垃圾收集时,我还想编写仍然健壮的代码.
所以 - 不用多说了,这里有一些代码说明:
class Foo
{
...
}
class Program
{
public static void fxn1(int blah)
{
...
}
public static void fxn2(Foo foo)
{
...
}
public static int ToInt(Foo foo)
{
...
}
public static void Main()
{
...
Foo foo = new Foo();
fxn2(foo); // I THINK foo may not be GC'ed until fxn2 returns...
// I THINK foo may be GC'ed here, even though CLR2.0 and CLR4.0 don't...
// (experiment shows CLR 2.0 and 4.0 leave foo "live" until Main returns)
fxn2(new Foo()); // I THINK the argument can't be GC'ed until fxn2 returns...
// I KNOW that even CLR2.0 and CLR4.0 will GC the argument after the return...
fxn1( ToInt(new Foo()) ); // I KNOW that new Foo is GC'able even within fxn1...
}
}
Run Code Online (Sandbox Code Playgroud)
因此,最终,现有CLR的规则似乎是:1.任何对象在函数调用期间是"活动的",它是一个直接参数2.任何对象在函数调用期间是"活动的"它由未重新分配的本地堆栈变量引用.(即使函数末尾的几条指令可能没有引用堆栈变量)
但是 - 显然C#保留修改(2)的权利,以便在函数内最终使用引用之前,对象是"实时"的.
这意味着:
Foo foo = new Foo();
Foo foo2 = new Foo();
fxn2(foo); // foo is NOT GC'able until fxn1 returns?
// foo IS GC'able from here on? (b/c no further uses of local "foo"?)
fxn2(foo2); // foo2 is NOT GC'able within fxn2 ?
fxn1(ToInt(foo2)); // foo2 IS GC'able within fxn1 ? (existing CLR does not GC foo2)
Run Code Online (Sandbox Code Playgroud)
ECMA规范中是否有任何内容可以详细处理垃圾收集资格?
好吧,这里不可能给出一般性答案,因为事情实际上符合GC的条件完全取决于运行时的实现.
唯一值得信赖的是保证 - 即,只要从堆栈中引用对象,就不会收集它.
但是,当从堆栈中删除局部变量时,您无法从代码中看出 - 这很容易在静态编译器和抖动中进行编译器优化.
因此,在运行时的下一次微小更新之后,现在可能不再是精确的答案了 - 通常最好编写不依赖于这些细微之处的代码,这些微妙之处只能通过实验找到,而是依赖于运行时的只保证.
@M.Babcock - 感谢您提供 ECMA 规范的链接!8.4 实际上太笼统了,但我正在寻找的答案是在 10.9 中 - 并且与 Java 相同 - 当一个变量不再被任何可能的未来代码路径引用时,那么它被认为有资格进行垃圾收集 - 这意味着尽管现有的 clr 实现似乎将局部变量生命周期限制在堆栈中,但不能保证第三方或未来的实现会这样做。
| 归档时间: |
|
| 查看次数: |
1272 次 |
| 最近记录: |