Wou*_*ort 13 c# console multithreading garbage-collection timer
以下代码是一个众所周知的示例,用于显示调试版本和发布版本之间的区别:
using System;
using System.Threading;
public static class Program
{
public static void Main()
{
Timer t = new Timer(TimerCallback, null, 0, 2000);
Console.ReadLine();
}
private static void TimerCallback(Object o)
{
Console.WriteLine("In TimerCallback: " + DateTime.Now);
GC.Collect();
}
}
Run Code Online (Sandbox Code Playgroud)
如果使用调试配置运行此命令,则计时器将每两秒输出当前时间.这GC.Collect没有任何影响,因为编译器人为地延长了Timer t变量的寿命.在发布配置中,计时器只执行一次.该GC.Collect遗嘱垃圾收集t变量,就是这样.
一切都像它应该的那样.奇怪的是,当您将Console.ReadLine行更改为Console.ReadKey时,两个配置每两秒运行一次计时器.
Console.ReadKey和Console.ReadLine有什么区别?我从文档中了解到Console.ReadKey阻塞了发出ReadKey方法的线程.但是GC.Collect仍然会发射..
为什么Timer t通过阻塞主线程来延长生命周期?
使用.NET 3.5时,不会发生此行为!
Ale*_*ese 10
该Console.ReadKey()方法锁定,Console.InternalSyncObject而Console.ReadLine()方法不锁定.当TimerCallBack()方法试图写入Console的Thread等待,因为Console.InternalSyncObject仍处于锁定状态.因此GC.Collect()从未被称为.一旦你按下一个键,锁就会被释放并被GC.Collect()调用.
我将您的代码更改为以下内容,但没有锁定Console.InternalSyncObject它,它只在Release中发出一次哔声,在Debug中每2秒发出一次哔声.
private static void TimerCallback(Object o)
{
Console.Beep();
GC.Collect();
}
Run Code Online (Sandbox Code Playgroud)
Console.WriteLine()等待的原因是它在第一次Console.InternalSyncObject创建时尝试获取锁定Console.Out TextWriter.
在我们创建Console.Out TextWriter启动计时器之前,将代码更改为以下代码可以正常工作.
public static void Main()
{
Console.WriteLine("Loaded");
Timer t = new Timer(TimerCallback, null, 0, 2000);
Console.ReadKey();
}
private static void TimerCallback(Object o)
{
Console.WriteLine("In TimerCallback: " + DateTime.Now);
GC.Collect();
}
Run Code Online (Sandbox Code Playgroud)
这是由于.NET 4.5的变化.更多信息在这里