I have a Blazor page which loads thousands of rows asynchronously. Within Visual Studio I see that once I load this data my Blazor app uses more than one gig in memory. No problem so far. However, the memory is not freed again when changing the page.
So I implemented IDisposable
which cancels the async operation and set my list with data to null but this does not seem to work as expected. The Dispose
method is called when the page is changed, but the memory consumption remains at 1 gigabyte.
Does anybody know what I did wrong?
Here is my code:
public List<ErloesKalkulatorServiceResult> Daten { get; set; } = new List<ErloesKalkulatorServiceResult>();
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
Daten = null!;
cancellationToken?.Cancel();
}
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
// TODO: set large fields to null
disposedValue = true;
}
}
~ErloesKalkulator()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: false);
}
public void Dispose()
{
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
I can tell you what I did in a similar situation. My app gets data from the database, populates a list which is used in the UI.
So in your code, put List.Clear() in the Dispose method of the page.
Then run the garbage collector. It really will reduce the heap size.
Originally, I did NOT use List.Clear(), and it did appear to me to never clear the data from memory. The app would grow in size until IIS took over and recycled the AppPool which forced the memory to be cleared. I am aware of the fact that such memory should be automatically cleared, but for me it was a problem as it appeared to be leaking memory.
However, you have to use the Diagnostic Tools Window within Visual Studio to see the actual heap size. If you are looking in the task manager, you will see only the amount of memory which is currently allocated to it as a whole. So it's not likely to reduce in size. However, if you looked in the Diagnostic Window and did a memory dump, you could see the actual current size of the heap and I bet you it would show you that the objects were in fact released, even if the app didn't let go of the memory.
Note that you should not be calling GC by hand except in usual circumstances like yours.
In the below screenshot, I called the GC for testing purposes using GC.Collect(). The second Snapshot shows the reduced memory. I have also reported this here: https://github.com/dotnet/aspnetcore/issues/39238