为什么我的Close函数没有被调用?

Roy*_*mir 10 .net c# clr garbage-collection finalizer

 class Program : CriticalFinalizerObject
    {
        static void Main(string[] args)
        {

            Program p = new Program();
            TextWriterTraceListener listener = new TextWriterTraceListener(@"C:\trace.txt");
            Trace.Listeners.Clear(); // Remove default trace listener
            Trace.Listeners.Add(listener);
            Trace.WriteLine("First Trace"); // Generate some trace messages
            Trace.WriteLine("Perhaps last Trace.");

        }

        ~Program()
        {
            Trace.Close();
        }
    }
Run Code Online (Sandbox Code Playgroud)

我得到文件大小= 0

finilizer 应该执行因为我来自CriticalFinalizerObject

我不想在Finalizer中使用Trace.Close().

编辑

@eric利珀特后答复:香港专业教育学院重新编辑的代码,试图把它匹配:约束的执行区域 (但仍然没有成功)

  [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    class Program : CriticalFinalizerObject
    {

        static void Main(string[] args)
        {
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
            }
            catch (Exception e)
            {
            }
            finally
            {
                Program p = new Program();
                TextWriterTraceListener listener = new TextWriterTraceListener(@"C:\trace1.txt");
                Trace.Listeners.Clear();
                Trace.Listeners.Add(listener);
                Trace.WriteLine("First Trace");
                Trace.WriteLine("Perhaps last Trace.");
            }
        }

        ~Program()
        {
            Trace.Flush();
        }
    }
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 11

正如文件明确指出:

在从CriticalFinalizerObject类派生的类中,公共语言运行库(CLR)保证所有关键的最终化代码都有机会执行,前提是终结器遵循CER的规则,即使在CLR强制卸载应用程序域的情况下也是如此或中止一个帖子.如果终结器违反了CER的规则,则可能无法成功执行

您的终结器是否遵循约束执行区域的所有规则?

更新:

您已经更新了代码,试图使其遵循约束执行区域的规则,但我没有看到您正确完成的任何证据.规则很清楚; 在受约束的执行区域中的终结器绝对不能执行以下任何操作:

  • 分配内存
  • 框一个值类型
  • 获得一把锁
  • 调用任意虚方法
  • 打电话给任何缺乏可靠性合同的方法

你的终结者会做这五件事吗?如果确实如此,则不要求CLR满足您对终结器始终运行的要求.

此外:暂时忘记约束执行区域,因为现在的程序甚至不是线程安全的.你已经在程序中写了一个讨厌的竞争条件.

在跟踪开始之前,什么阻止了垃圾收集p的抖动?没有!抖动知道p将永远不会再次使用,完全在其分配后立即收集它的权利.冲洗可能会发生在任何时间终结器线程上,包括之前跟踪写入发生,或在任何他们的中间.

  • 你应该告诉我们答案,Eric,如果你想要这个答案...... ;-) (3认同)
  • **ProTip:**编写_reliable_(CER相关)代码具有挑战性.如果您不完全了解解决方案领域中的工具,您可能会搞砸它. (3认同)

Ser*_*kiy 10

因为您没有创建Program类的实例.

你可以在这里阅读更多:

在对象变得不可访问之后自动调用此方法,除非通过调用SuppressFinalize来豁免对象的最终化.在关闭应用程序域期间,会自动调用Finalize,这些对象不会被终止,即使是那些仍然可访问的对象.Finalize在给定实例上仅自动调用一次,除非使用ReRegisterForFinalize和GC等机制重新注册该对象.随后未调用GC.SuppressFinalize.

所以,如果你想要调用finilizer,你需要有对象的实例.

更新:Trace.AutoFlush = true;如果您想要写入消息,请考虑使用.

更新:(为什么不调用Close函数?)实际上你调用了Close函数(如果在其他终结器中没有例外).如果你保持默认的TraceListener(删除Trace.Listeners.Clear()调用),你会看到所有字符串都成功写入Output窗口.

这里的问题是StreamWriter(在TextWriterTraceListener中创建)没有终结器.因此它不会将所有数据刷新到文件.你需要做什么:

FileStream file = new FileStream(@"C:\trace.txt", FileMode.OpenOrCreate);
StreamWriter writer = new StreamWriter(file);
GC.SuppressFinalize(file);
GC.SuppressFinalize(file.SafeFileHandle);
var listener = new TextWriterTraceListener(writer);
Run Code Online (Sandbox Code Playgroud)

实际上,您需要在终结器上手动关闭文件.

  • @RoyiNamir:您能否请更新您的代码以显示`Program`类的实例化,以便其他人不会得出同样的结论? (5认同)
  • 整个问题是我通过学习GC内部的旅行... :)所以我宁愿不使用`Trace.AutoFlush`但要学习为什么它不被调用. (3认同)