简体   繁体   中英

Blazor: Update using InvokeAsync causes memory leak

I have a Blazor app with a list that I want to update automatically using a Timer every X seconds. When I run the app using the following code, the list is refreshed every 10 seconds, but the memory usage rises on every refresh. The memory usage of the app starts at 2-300 MB and rises past 1 GB within 10 refreshes.

I was hoping that my code would overwrite the existing list on every refresh, thus not using more and more memory. What am I missing? Could it be because the refreshing is done in multiple threads?

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

It seems the issue here is not in the code provided, but the statement _myService.GetList(). As @HenkHolterman has keenly observed, the only memory-leak in this code is that the timer is not disposed of when the component is no longer in use. This can be done like:

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

    //other code.....

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM