如何在 Blazor 应用程序中制作我的计时器泄漏证明?

How can I make my Timer leaking proof in Blazor App?

我已经在 Whosebug 中发布了一个问题的答案。答案如下:

您可以创建一个可以在很多场合为您服务的定时服务:

创建服务 class:

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 容器,在 Program.Main 方法中,作为瞬态:

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;
}

}

然而,有人告诉我

the BlazorTimer is leaking the _timer. Timer is IDisposable

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

BlazorTimer 应该实现 IDisposable。 BlazorTimer Dispose 方法应停止计时器、取消订阅 Elapsed 事件并释放计时器。

问题的根源是您的 BlazorTimer 被设置为 Transient 服务。因此,对于每个新请求,您都会获得带有新 .Net 计时器的新 BlazorTimer 对象,这些计时器永远不会被正确处理

好的,感谢 mkArtakMSFT and Peter Morris

我已经解决了这个问题

The general rule of thumb is that every time you encapsulate a disposable type in a new type as a member, you should make your new type disposable too. In your particular case, the BlazorTimer class is not disposable - hence the underlying _timer instance, when initialized, never gets disposed of - leaving some memory behind.

Furthermore, every time the SetTimer method is called, a new Timer instance is being created, and the old one is being left behind (in the air), again leaking memory. Consider disposing of existing instance, if that's your intent. Or, even better, reuse existing instance if that would be acceptable for your business rules Source

注意:“BlazorTimer class 不是一次性的”,因为我使用的是瞬态依赖项。将其作为一次性使用会产生不利影响...请参阅解释 blazor-university

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