代码之家  ›  专栏  ›  技术社区  ›  enet

如何在Blazor应用程序中防止计时器泄漏?

  •  0
  • enet  · 技术社区  · 5 年前

    我在stackoverflow中发布了一个问题的答案 C# counter to count up to a target number .答案如下:

    您可以创建一个计时器服务,它可以在多种情况下为您服务:

    创建服务类:

    public class BlazorTimer
        {
            private Timer _timer;
    
            internal void SetTimer(double interval)
            {
                _timer = new Timer(interval);
                _timer.Elapsed += NotifyTimerElapsed;
                _timer.Enabled = true;
                _timer.Start();
            }
    
            private void NotifyTimerElapsed(object sender, ElapsedEventArgs e)
            {
                OnElapsed?.Invoke();
            }
    
            public event Action OnElapsed;
        }
    

    将服务添加到程序中的DI容器中。主要方法,如瞬态:

    builder.Services.AddTransient(config =>
            {
                var blazorTimer = new BlazorTimer();
                blazorTimer.SetTimer(1000);
                return blazorTimer;
            });
    

    用法

    @page "/"
    
    @implements IDisposable
    @inject BlazorTimer Timer
    
    @count.ToString()
    
    
    @code{
    private int count = 0;
    
    protected override void OnInitialized()
    {
        Timer.OnElapsed += NotifyTimerElapsed;
    
        base.OnInitialized();
    }
    
    private void NotifyTimerElapsed()
    {
        // Note: WebAssembly Apps are currently supporting a single thread, which 
        // is why you don't have to call
        // the StateHasChanged method from within the InvokeAsync method. But it 
        // is a good practice to do so in consideration of future changes, such as 
        // ability to run WebAssembly Apps in more than one thread.
        InvokeAsync(() => { count++; StateHasChanged(); });
    }
    
    public void Dispose()
    {
        Timer.OnElapsed -= NotifyTimerElapsed;
    }
    
    }
    

    然而,有人告诉我

    BlazorTimer正在泄漏\u计时器。计时器可识别

    取消订阅Blazor组件中实现的Dispose方法中的事件处理程序是否会导致 BlazorTimer泄漏\u计时器。实际上,我并不完全理解“BlazorTimer正在泄漏\u计时器。计时器是IDisposable的”,所以让我问一下,如何防止计时器泄漏,同时使用代码取消订阅Blazor组件中实现的Dispose方法中的事件处理程序?除了跳过事件处理程序的取消订阅之外,是否有其他方法可以防止此泄漏。

    0 回复  |  直到 5 年前
        1
  •  2
  •   Stellarade    5 年前

    BlazorTimer应该实现IDisposable。BlazorTimer Dispose方法应停止计时器,取消订阅已用事件,然后处置计时器。

    问题的根源是BlazorTimer被设置为临时服务。因此,对于每个新请求,您都会得到新的BlazorTimer对象。无法正确处理的Net计时器

        2
  •  0
  •   enet    5 年前

    好的,多亏了 mkArtakMSFT 和 Peter Morris 。

    一般的经验法则是,每次封装 一次性类型在新类型中作为成员,您应该 也输入一次性。在您的特定情况下,BlazorTimer类是 不是一次性的-因此,当 初始化后,永远不会被丢弃-留下一些内存。

    此外,每次调用SetTimer方法时,都会有一个新的计时器 实例正在创建中,旧的实例正在被丢弃(在 空气),再次泄漏内存。考虑处置现有 例如,如果这是你的意图。或者,更好的是,重用现有的 实例,如果您的业务规则可以接受 Source

    注意:“BlazorTimer类不是一次性的”,因为我使用的是瞬态依赖项。将其作为一次性使用将产生不利影响。。。请参见说明 blazor-university

    为了解决内存泄漏问题,在我当前的代码段中,我应该简单地从notifyTimeRecursed方法调用Timer对象上的Dispose方法(总是这样做,这次忘记了它)