【问题标题】:Blazor: Update using InvokeAsync causes memory leakBlazor:使用 InvokeAsync 更新会导致内存泄漏
【发布时间】:2021-03-14 14:45:45
【问题描述】:

我有一个 Blazor 应用程序,其中有一个列表,我想使用计时器每隔 X 秒自动更新一次。当我使用以下代码运行应用程序时,列表每 10 秒刷新一次,但每次刷新时内存使用量都会增加。应用程序的内存使用量从 2-300 MB 开始,并在 10 次刷新内超过 1 GB。

我希望我的代码在每次刷新时都会覆盖现有列表,从而不会使用越来越多的内存。我错过了什么?难道是因为刷新是在多个线程中完成的?

public partial class MyBlazorComponent
{
    private Dictionary<Guid, IList<MyModel>> MyList { get; set; }
    private Timer Timer { get; set; }
    
    // A simple lock to make sure that multiple refreshes don't overlap
    private bool _isRefreshing;

    protected override async Task OnInitializedAsync()
    {
        await UpdateMyList(); // the initial loading of the list
        await base.OnInitializedAsync();

        Timer = new Timer(async _ =>
        {
            await RefreshList();
        }, null, 0, 10000);
    }

    private async Task UpdateMyList()
    {
        _isRefreshing = true;
        MyList = null;
        MyList = await _myService.GetList(); // external service to get list contents
        _isRefreshing = false;
    }
    
    private async Task RefreshList()
    {
        if (!_isRefreshing)
        {
            // Without these two lines, the list won't update
            MyList = null; 
            await InvokeAsync(StateHasChanged);
            
            // Update the list
            await UpdateMyList();
            await InvokeAsync(StateHasChanged);
        }
    }
}

【问题讨论】:

  • 我制作了您共享的代码的一个小版本 (blazorfiddle.com/s/sr0spgs8),但我没有遇到您所描述的问题。当我在本地运行它时,我也没有注意到内存泄漏。还有一点需要特别注意的是,我不需要调用两次 StateHasChanged 来更改列表。您能否分享一些剃须刀代码以及有关服务的更多详细信息?对我来说,问题似乎不在您提供的代码中。
  • 你为什么用StateHasChanged,更不用说InvokeAsync(StateHasChanged)?替换列表将导致仅重绘受影响的元素。 StateHasChanged 将触发整个页面的更新。 InvokeAsync .... 这有什么意义?您是否尝试过在计时器中简单地调用UpdateMyList
  • 顺便说一句,您使用的是哪个 Blazor 版本?服务器端还是 Web 程序集? 需要 Blazor 版本 StateHasChanged,.NET 5 不需要
  • 旁注,您正在泄漏计时器,但这不会导致您看到的内存使用。
  • 完全忽略了@HenkHolterman。这确实应该实现 IDispose 以摆脱不再使用的计时器。

标签: blazor


【解决方案1】:

看来这里的问题不在于提供的代码,而在于语句_myService.GetList()。正如@HenkHolterman 敏锐地观察到的那样,此代码中唯一的内存泄漏是当组件不再使用时计时器不会被释放。这可以像这样完成:

public partial class MyBlazorComponent : IDisposable
{
    private Timer Timer { get; set; }

    //other code.....

    public void Dispose()
    {
        Timer?.Dispose();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-09
    • 2021-09-02
    • 2010-11-18
    • 1970-01-01
    • 2021-03-23
    • 2021-09-25
    相关资源
    最近更新 更多