Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 特例寿命分析_C#_Garbage Collection - Fatal编程技术网

C# 特例寿命分析

C# 特例寿命分析,c#,garbage-collection,C#,Garbage Collection,如果我有 void foo () { Bar bar = new Bar(); // bar is never referred to after this line // (1) doSomethingWithoutBar(); } 在(1)处,指向垃圾收集的对象条是否符合条件?还是bar也必须不在范围之内?如果doSomethingWithoutBar调用GC.Collect,会有区别吗 这与了解Bar是否有(C#)析构函数或类似的东西有关。一旦确定不再使用对象,它

如果我有

void foo () {
    Bar bar = new Bar(); // bar is never referred to after this line
    // (1)
    doSomethingWithoutBar();
}
在(1)处,指向垃圾收集的对象
条是否符合条件?还是
bar
也必须不在范围之内?如果
doSomethingWithoutBar调用
GC.Collect
,会有区别吗


这与了解Bar是否有(C#)析构函数或类似的东西有关。

一旦确定不再使用对象,它们就可以进行垃圾收集。在变量超出范围之前,
bar
完全有可能被垃圾收集

证明:

using System;

class Bar
{
    ~Bar() { Console.WriteLine("Finalized!"); }
}

class Program
{
    static void Main(string[] args)
    {
        Bar bar = new Bar();
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Console.WriteLine("Press any key to exit...");
        Console.ReadLine();
    }
}
在发布模式下运行(因为它不会在调试模式下被收集)

输出:

Finalized! Press any key to exit... 定稿! 按任意键退出。。。
它也适用于使用单声道的系统。输出是相同的。

如果不定义您所指的CLR版本,就很难确定您将在此处看到的行为

在本例中,假设的CLR可以假设以下情况为真:

  • Bar
    的构造函数不执行任何操作
  • 没有初始化的字段(即,对象构造没有潜在的副作用)
  • 完全忽略行
    Bar=newbar()并优化它,因为它“什么都不做”


    就我的记忆而言,在当前版本的CLR
    中,bar
    可以在构建之后立即进行垃圾收集。

    快速阅读规范,它看起来是特定于实现的。允许对其进行垃圾收集,但不要求进行垃圾收集

    我从以下第10.9节“自动内存管理”中的注释中得到:

    [注意:实现可能会选择分析代码以确定 将来可以使用对对象的哪些引用。对于 实例,如果作用域中的局部变量是唯一存在的 引用对象,但该局部变量从未被引用 在当前执行的任何可能的继续执行中 在过程中,实现可能(但不是必需的) 将对象视为不再使用。结束注释]


    强调我的问题。

    马克回答了这个问题,但以下是解决方案:

    void foo () {
        Bar bar = new Bar(); // bar is never referred to after this line
        // (1)
        doSomethingWithoutBar();
    
        GC.KeepAlive(bar); // At the point where you no longer need it
    }
    

    这肯定会发生。例如,这里演示了一个实例可以在您仍在执行其构造函数时完成:

    class Program
    {
        private static int _lifeState;
        private static bool _end;
    
        private sealed class Schrodinger
        {
            private int _x;
    
            public Schrodinger()
            {
                //Here I'm using 'this'
                _x = 1;
    
                //But now I no longer reference 'this'
                _lifeState = 1;
    
                //Keep busy to provide an opportunity for GC to collect me
                for (int i=0;i<10000; i++)
                {
                    var garbage = new char[20000];
                }
    
                //Did I die before I finished being constructed?
                if (Interlocked.CompareExchange(ref _lifeState, 0, 1) == 2)
                {
                    Console.WriteLine("Am I dead or alive?");
                    _end = true;
                }
            }
    
            ~Schrodinger()
            {
                _lifeState = 2;
            }
        }
    
        static void Main(string[] args)
        {
            //Keep the GC churning away at finalization to demonstrate the case
            Task.Factory.StartNew(() =>
                {
                    while (!_end)
                    {
                        GC.Collect();
                        GC.WaitForPendingFinalizers();
                    }
                });
    
            //Keep constructing cats until we find the desired case
            int catCount = 0;
            while (!_end)
            {
                catCount++;
                var cat = new Schrodinger();
                while (_lifeState != 2)
                {
                    Thread.Yield();
                }
            }
            Console.WriteLine("{0} cats died in the making of this boundary case", catCount);
            Console.ReadKey();
        }
    }
    
    类程序
    {
    私有静态int_lifeState;
    专用静态bool_end;
    私人密封类薛定谔方程
    {
    私人互联网;
    公共薛定谔方程()
    {
    //这里我用的是“this”
    _x=1;
    //但现在我不再提及“这”
    _生命状态=1;
    //保持忙碌,为GC提供收集我的机会
    对于(int i=0;i
    {
    while(!\u结束)
    {
    GC.Collect();
    GC.WaitForPendingFinalizers();
    }
    });
    //继续构建猫,直到我们找到想要的案例
    int catCount=0;
    while(!\u结束)
    {
    catCount++;
    var cat=新的薛定谔方程();
    而(_lifeState!=2)
    {
    螺纹屈服强度();
    }
    }
    WriteLine({0}只猫在制作这个边界案例时死亡),catCount);
    Console.ReadKey();
    }
    }
    
    为了使其正常工作,您需要发出一个发布版本并在Visual Studio外部运行它(否则调试器会插入阻止此效果的代码)。我已经使用VS 2010 Targeting.NET 4.0 x64对其进行了测试


    你可以调整“保持忙碌”循环中的迭代次数,以影响猫在完成构建之前结束的概率。

    我只想等待Eric Lippert过来处理这个问题…@StefanH,我想我已经看到Eric对一个非常类似的问题的回答(或者他的博客)但是我的google fu现在失败了=(@Rob-我知道!我试着在google上搜索“C#Garbage Collection”,因为我认为他将是第一个结果。仅供参考,这些情况下的常见做法(或者更常见的情况是,当非托管资源需要保持活动状态时),将要使用。我认为它将等待作用域完成,以确保没有对该局部对象的任何运行时引用。@Tigran,因为它是一个局部变量,在运行时怎么可能有对它的引用?=)我无法重现这种情况。在任何版本的框架中:2、3.0、3.5、4.0。@Hailton:您是否尝试在发布模式下运行它?我使用Visual Studio C#2010 Express(C#4)对其进行了测试在发布模式下。您可以单击ideone链接并查看输出-它也在那里工作。我还简化了代码。您只需将其复制并粘贴到新的控制台项目中,切换到发布模式,然后按F5。我使用这些说明更改Visual Studio Express以在发布模式下生成:是的,您是对的。在发布模式下,我将因为我能够重现这种情况。谢谢你的澄清。我有一个问题:我做了一个类似的代码,但不能做GC来收集对象。我将用这段代码作为一个新问题发布。我想你是指一个“假想的编译器”@StefanH,如果“假想的编译器”你是指“假想的JIT编译器”,那么是的,这就是我的意思=)否则
    Bar
    可以在另一个程序集中定义,可以在编译后替换掉
    csc
    compile,导致编译时的
    Bar
    被剥离,即使运行时的
    Bar
    可能会做些什么…(将插件开发视为一种可能的场景)我更多的是想在创建CLR之前,也就是在编译时,它会被剥离掉,对吗?编辑:不,我只是错了(CLR并不是我所想的意思),我想它可能会在生成CIL之前被剥离掉。CLR