gpt4 book ai didi

c# - Garbage Collector、call & callvirt 和 Debug/Release 代码模式执行差异

转载 作者:行者123 更新时间:2023-12-03 20:35:23 25 4
gpt4 key购买 nike

我有一个类:

public class SomeClass {
public int I;

public SomeClass(int input) {
I = input;
Console.WriteLine("I = {0}", I);
}

~SomeClass() {
Console.WriteLine("deleted");
}

public void Foo() {
Thread.Sleep(1000);
Console.WriteLine("Foo");
}
}

和这个程序:

class Program {
static void Main(string[] args) {
new Thread(() => {
Thread.Sleep(100);
GC.Collect();
}) { IsBackground = true }.Start();

new SomeClass(10).Foo();

// The same as upper code
// var t = new SomeClass(10);
// t.Foo();
}
}

当我在 Debug模式中运行这段代码时,我得到了下一个结果:

I = 10
Foo
deleted

但是,当我将模式更改为发布时,结果更改为:

I = 10
deleted
Foo

据我了解,callcallvirt 存在差异:当优化以Release 模式开始时,编译器查看Foo 方法并且在这个方法中找不到任何对 SomeClass 的引用,这就是为什么这个方法通过地址调用静态方法,并且 垃圾收集器 可以收集这个对象。

否则,如果我更改 Foo 方法(例如,将 Console.WriteLine(I) 添加到此方法中),编译器将不会决定调用此方法作为call 并且它应该通过指向实例的指针调用 callvirt 并且垃圾收集器不会收集这个对象。

能否请您更清楚地解释一下,这里发生了什么(为什么 GC 可以收集对象,如果是这样,方法调用是如何进行的)。

最佳答案

我怀疑它真的与 callcallvirt 有任何关系。

我强烈怀疑这仅仅是因为您没有使用 SomeClass.Foo 中的任何字段。当确定不会再次引用任何数据时,垃圾收集器可以自由地收集对象 - 因此没有代码会查看对该对象的任何引用或对象中的任何字段。

基本上,如果您编写终结器并且需要确保在该对象内的方法运行时对象未终结,则您需要非常小心。您可以在方法末尾使用 GC.KeepAlive(this) 作为一种方法,但它有点难看。如果可以的话,我个人会非常努力地避免使用终结器。我不记得我最后一次写一个。 (有关更多信息,请参阅 Joe Duffy's blog。)

当附加了调试器时,GC 对它可以收集的内容的积极性 - 毕竟,如果您可以在任何时候闯入调试器并检查任何对象的字段正在运行的实例方法的目标,它消除了垃圾收集这些对象的可能性。

关于c# - Garbage Collector、call & callvirt 和 Debug/Release 代码模式执行差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21571291/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com