A. System.Threading vs System.Timers
值得指出的是,保留引用问题是特定于 System.Threading.Timer 而不是 System.Timers.Timer。
B. Threading.Timer的Timer(TimerCallback callback)构造函数
这不是您问题的解决方案,但我认为它仍然与主题相关。
System.Threading.Timer 的Timer(TimerCallback callback) 构造函数(不使用dueTime 和其他构造函数的构造函数)使用this 代替state,这意味着计时器将保留对自身的引用,这意味着它将在垃圾收集中幸存下来。
public Timer(TimerCallback callback)
{
(...)
TimerSetup(callback, this, (UInt32)dueTime, (UInt32)period, ref stackMark);
}
示例
计时器“C”是使用Timer(TimerCallback callback) 创建的,它一直在GC.Collect() 之后运行。
输出
A
B
C
A
B
C
GC Collected
B
C
C
B
B
C
代码
class TimerExperiment
{
System.Threading.Timer timerB;
public TimerExperiment()
{
StartTimer("A"); // Not keeping this timer
timerB = StartTimer("B"); // Keeping this timer
StartTimer2("C"); // Not keeping this timer
}
static System.Threading.Timer StartTimer(string name) {
return new System.Threading.Timer(_ =>
{
Console.WriteLine($"{name}");
}, null, dueTime: Delay(name), period: TimeSpan.FromSeconds(1));
}
static System.Threading.Timer StartTimer2(string name)
{
//Create the timer using the constructor which only takes the callback
var t = new System.Threading.Timer( _ => Console.WriteLine($"{name}"));
t.Change(dueTime: Delay(name), period: TimeSpan.FromSeconds(1));
return t;
}
static TimeSpan Delay(string name)
=> TimeSpan.FromMilliseconds(Convert.ToInt64(name[0])*10);
}
class Program
{
static async Task Main(string[] args)
{
var withTimers = new TimerExperiment();
await Task.Delay(TimeSpan.FromSeconds(2));
GC.Collect();
Console.WriteLine("GC Collected");
Console.ReadLine();
}
}