关于.NET Core中System.Threading.Timer在Linux服务仅触发一次的问题咨询
System.Threading.Timer在Linux下仅触发一次的问题
我之前也碰到过完全一样的情况!当时排查了好久才揪出根源,核心是.NET跨平台下的GC行为差异搞的鬼。
问题本质
System.Threading.Timer的实例如果没有被强引用持续持有,在Linux的GC策略下会被快速回收——因为它内部依赖弱引用机制来管理生命周期。而Windows环境里,要么调试器会自动阻止GC回收这类对象,要么默认GC策略更宽松,所以定时器能正常周期性触发。
举个典型的错误写法,很容易踩这个坑:
// 错误示例:局部变量的Timer,方法执行完就会失去引用 void StartTimer() { var timer = new System.Threading.Timer(Callback, null, TimeSpan.Zero, TimeSpan.FromSeconds(1)); }
这种代码在Windows调试时可能一切正常,但发布到Linux后,方法执行完毕局部变量timer就没了引用,GC一回收定时器就停了,自然只会触发一次。
可行的解决办法
除了你已经改用的System.Timers.Timer(它内部会自动持有自身的强引用),还可以给System.Threading.Timer手动加个强引用:
// 正确示例:把Timer存在类字段里,保持持续引用 private System.Threading.Timer _timer; void StartTimer() { _timer = new System.Threading.Timer(Callback, null, TimeSpan.Zero, TimeSpan.FromSeconds(1)); }
只要类实例还存活,_timer就不会被GC回收,定时器就能正常周期性触发。
当时的排查小技巧
我当时还通过这些方式验证了问题:
- 在回调方法里打印
GC.GetTotalMemory(false),观察GC触发时机和定时器停止的关联 - 使用
dotnet dump工具分析内存,确认Timer实例是否真的被回收
不少同行都遇到过这个坑,主要是忽略了System.Threading.Timer的引用特性,再加上跨平台GC行为的差异,才导致了这种“Windows正常、Linux异常”的诡异情况。
内容的提问来源于stack exchange,提问作者Clarke76
相关产品推荐
相关产品推荐

