垃圾收集器,通话和放大器; callvirt和调试/发布代码执行模式的差异 [英] Garbage Collector, call & callvirt and Debug/Release code mode execution differences

查看:112
本文介绍了垃圾收集器,通话和放大器; callvirt和调试/发布代码执行模式的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类:

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();
    }
}

当我运行中的调试模式下,该代码,我有一个结果:

When i run this code in Debug mode, i have next result:

I = 10
Foo
deleted

但是,当我改变模式为发布,结果改为:

but, when i change mode to Release, result changes to:

I = 10
deleted
Foo

据我了解,有一个与区别呼叫 callvirt :当优化在开始的发布模式中,编译器看看方法无法找到 SomeClass的在此方法中,这就是为什么这种方法,通过地址调用静态方法,和垃圾收集会收集这些对象。

As i understand, there is difference with call and callvirt: when optimization starts in Release mode, compiler look at Foo method and can't find any reference to SomeClass in this method, and that's why this method calls as static method by address, and garbage collector could collect this object.

否则,如果我改变方法(例如,添加 Console.WriteLine(I)进入此方法),编译不会决定调用此方法为呼叫,它应该通过指针实例 callvirt 被称为和垃圾收集将不收取此对象。

Otherwise, if i change Foo method (for example, add Console.WriteLine(I) into this method), compiler won't decide to call this method as call and it should be called by pointer to instance with callvirt and garbage collector won't collect this object.

能否请你解释清楚,这是怎么回事上(为什么 GC 可以收集对象,如果是这样,怎么做方法调用)。

Can you please explain more clearly, what's going on here (why GC could collect object and if it's so, how does method calls).

推荐答案

我怀疑它真的什么关系呼叫 callvirt

I doubt that it's really anything to do with call and callvirt.

我强烈怀疑这只是因为你再没有使用在 SomeClass.Foo 的任何字段。垃圾收集器是免费的收集对象时,可以肯定的是没有数据将再次引用的 - 所以没有代码是要去看看的对象,或者对象中的任何领域的任何引用

I strongly suspect it's simply because you're not using any fields within SomeClass.Foo. The garbage collector is free to collect an object when it is certain that none of the data will be referenced again - so no code is going to look at any references to the object, or any fields within the object.

基本上,如果你写一个终结,你需要确保而对象中的方法,正在运行的对象没有最终确定,你需要的非常的小心。你可以在方法的结尾使用 GC.KeepAlive(本),作为一种方式,但它是一个有点难看。 ,如果可以的话我个人非常努力,以避免需要一个终结的。我不记得上一次我写的。 (请参见乔·达菲的更多的博客)。

Basically, if you write a finalizer and you need to ensure that the object isn't finalized while methods within that object are running, you need to be very careful. You can use GC.KeepAlive(this) at the end of methods, as one approach, but it's a bit ugly. I would personally try very hard to avoid needing a finalizer at all, if you can. I can't remember the last time I wrote one. (See Joe Duffy's blog for more.)

当有附加调试器,在GC的的什么它可以收集较少攻击性 - 毕竟,如果你能进入调试器在任何点,并检查是正在运行的实例方法的目标的任何对象的字段,用于删除垃圾收集那些对象的可能性。

When there's a debugger attached, the GC is much less aggressive about what it can collect - after all, if you can break into the debugger at any point and inspect the fields of any object that is the target of a running instance method, that removes the possibility of garbage collecting those objects.

这篇关于垃圾收集器,通话和放大器; callvirt和调试/发布代码执行模式的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆