完成并 GC.Collect
Finilize and GC.Collect
我试图理解为什么会有不同的行为。
代码 1 不同于 代码 2 只是注释行 Console.WriteLine(h.ToString());
.
但在这种情况下 Console.Beep();
在 代码 1 执行 before static void Main(string[] args)
完成。
在 代码 2 Console.Beep();
仅在 static void Main(string[] args)
完成(进程终止?)时执行。
你能解释一下吗,为什么会这样?
我尝试使用 [+/-] 优化设置调用代码 - 看起来它不依赖于它。
现在我没有 WinDbg,- mb 反编译代码中的答案。
代码 1:
class Program
{
static void Main(string[] args) {
var h = new Haha();
// Console.WriteLine(h.ToString());
GC.Collect();
GC.WaitForPendingFinalizers();
/* Console.Beep() calls here */
Console.ReadKey();
}
}
public class Haha
{
~Haha() {
Console.Beep();
}
}
代码 2:
class Program
{
static void Main(string[] args) {
var h = new Haha();
Console.WriteLine(h.ToString());
GC.Collect();
GC.WaitForPendingFinalizers();
Console.ReadKey();
/* Console.Beep() calls here */
}
}
public class Haha
{
~Haha() {
Console.Beep();
}
}
在第一个例子中:
var h = new Haha()
该变量未在任何地方引用,因此已将其删除。这样Haha()创建后就不会在任何地方被引用,随时可以被GC
在第二个示例中,变量 h
被引用,因此它在引用它的块中具有 "maximum" 生命周期(因此整个 main
)。编译器和 GC 可以检测到 "last" 对 h
的使用,并认为它在 Console.WriteLine
(最后一次使用 h
)之后未被引用(缩短其生命周期) ,但显然不要这样做。
请注意,如果你 运行 你的程序处于发布模式 + 运行 没有调试器,代码 2 将给出(至少它给我)与代码 1 相同的结果。调试器,为了更容易调试,保证所有引用在声明它们的块结束之前都是有效的(参见 )运行在发布模式下运行程序 + 运行没有调试器,我们解决了这个问题。
进行了一些测试:为了缩短生命周期,您需要(同时):[=37= 处的调试信息(属性->构建->高级->调试信息) ] 或 pdb-only,加上 运行 没有调试器 (Ctrl+F5) 的程序。如果将 Debug Info 设置为 Full,则会在程序集中注入 DebuggableAttribute
,并且 CLR 不会尝试缩短变量的生命周期。如果您 运行 使用调试器,则相同。如果通过命令行编译,设置选项 /debug
等同于 /debug:full
(参见 https://msdn.microsoft.com/en-us/library/8cw0bt21.aspx)
我试图理解为什么会有不同的行为。
代码 1 不同于 代码 2 只是注释行 Console.WriteLine(h.ToString());
.
但在这种情况下 Console.Beep();
在 代码 1 执行 before static void Main(string[] args)
完成。
在 代码 2 Console.Beep();
仅在 static void Main(string[] args)
完成(进程终止?)时执行。
你能解释一下吗,为什么会这样?
我尝试使用 [+/-] 优化设置调用代码 - 看起来它不依赖于它。
现在我没有 WinDbg,- mb 反编译代码中的答案。
代码 1:
class Program
{
static void Main(string[] args) {
var h = new Haha();
// Console.WriteLine(h.ToString());
GC.Collect();
GC.WaitForPendingFinalizers();
/* Console.Beep() calls here */
Console.ReadKey();
}
}
public class Haha
{
~Haha() {
Console.Beep();
}
}
代码 2:
class Program
{
static void Main(string[] args) {
var h = new Haha();
Console.WriteLine(h.ToString());
GC.Collect();
GC.WaitForPendingFinalizers();
Console.ReadKey();
/* Console.Beep() calls here */
}
}
public class Haha
{
~Haha() {
Console.Beep();
}
}
在第一个例子中:
var h = new Haha()
该变量未在任何地方引用,因此已将其删除。这样Haha()创建后就不会在任何地方被引用,随时可以被GC
在第二个示例中,变量 h
被引用,因此它在引用它的块中具有 "maximum" 生命周期(因此整个 main
)。编译器和 GC 可以检测到 "last" 对 h
的使用,并认为它在 Console.WriteLine
(最后一次使用 h
)之后未被引用(缩短其生命周期) ,但显然不要这样做。
请注意,如果你 运行 你的程序处于发布模式 + 运行 没有调试器,代码 2 将给出(至少它给我)与代码 1 相同的结果。调试器,为了更容易调试,保证所有引用在声明它们的块结束之前都是有效的(参见 )运行在发布模式下运行程序 + 运行没有调试器,我们解决了这个问题。
进行了一些测试:为了缩短生命周期,您需要(同时):[=37= 处的调试信息(属性->构建->高级->调试信息) ] 或 pdb-only,加上 运行 没有调试器 (Ctrl+F5) 的程序。如果将 Debug Info 设置为 Full,则会在程序集中注入 DebuggableAttribute
,并且 CLR 不会尝试缩短变量的生命周期。如果您 运行 使用调试器,则相同。如果通过命令行编译,设置选项 /debug
等同于 /debug:full
(参见 https://msdn.microsoft.com/en-us/library/8cw0bt21.aspx)