Oro*_*div 5 .net c# multithreading timer
有时,用户希望安排大量计时器,并且不希望管理对这些计时器的引用.
在用户没有引用计时器的情况下,GC可以在执行之前收集计时器.
我创建了类Timers作为新创建的计时器的占位符:
static class Timers
{
private static readonly ILog _logger = LogManager.GetLogger(typeof(Timers));
private static readonly ConcurrentDictionary<Object, Timer> _timers = new ConcurrentDictionary<Object, Timer>();
/// <summary>
/// Use this class in case you want someone to hold a reference to the timer.
/// Timer without someone referencing it will be collected by the GC even before execution.
/// </summary>
/// <param name="dueTime"></param>
/// <param name="action"></param>
internal static void ScheduleOnce(TimeSpan dueTime, Action action)
{
if (dueTime <= TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException("dueTime", dueTime, "DueTime can only be greater than zero.");
}
Object obj = new Object();
Timer timer = new Timer(state =>
{
try
{
action();
}
catch (Exception ex)
{
_logger.ErrorFormat("Exception while executing timer. ex: {0}", ex);
}
finally
{
Timer removedTimer;
if (!_timers.TryRemove(obj, out removedTimer))
{
_logger.Error("Failed to remove timer from timers");
}
else
{
removedTimer.Dispose();
}
}
});
if (!_timers.TryAdd(obj, timer))
{
_logger.Error("Failed to add timer to timers");
}
timer.Change(dueTime, TimeSpan.FromMilliseconds(-1));
}
}
Run Code Online (Sandbox Code Playgroud)
如果我不处理已移除的计时器,则会导致内存泄漏.
似乎有人在从_timers集合中删除计时器后持有对Timer的委托的引用.
问题是,如果我不处理计时器,为什么会出现内存泄漏?
将Timer 通过保持活动GCHandle由定时器自身创建的.这可以使用.net内存分析器进行测试.反过来Timer,这将使代表保持活力,这将使其余的活着.
A GCHandle是一种特殊的对象,可用于"欺骗"垃圾收集器以使不可达的对象保持活动状态.
实际上你可以在没有分析器的情况下测试这个:
var a = new ClassA();
var timer = new Timer(a.Exec);
var refA = new WeakReference(a);
var refTimer = new WeakReference(timer);
a = null;
timer = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.WriteLine(refA.IsAlive);
Console.WriteLine(refTimer.IsAlive);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3443 次 |
| 最近记录: |