dotnet / aspnetcore

ASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.
https://asp.net
MIT License
34.89k stars 9.85k forks source link

Blazor Server-Side: Circuits/memory leak? #42106

Closed nzdvis closed 2 years ago

nzdvis commented 2 years ago

Is there an existing issue for this?

Describe the bug

We host our Blazor site in AKS (Azure Kubernetes Service), and I got notified that the site was climbing fast in memory usage. I thought that something was wrong with some of my components, but no memory leak what so ever was wrong with them, or some of the third-party components we use.

The site is designed to be integrated in slideshows (They browse the URL and get some graphs displayed). We currently have one customer testing the solution.

  1. They open the site wait for 15 seconds
  2. Then browse to another page
  3. Then when the cycle is done, that start over again

So they visit our page once every minut.

I then tried to simulate the scenario (Just by hitting F5 every 15 seconds): Diagnostics session: image

Azure newly uploadet memory usage: image

Azure after 5 min memory usage: image

I then tried with a cleanly new Blazor Server-Side project, and the same thing happend (Not the same memory amount was used, but it was still climbing).

Then I thought it could be circuit build-up, so I tried to remove and change retention period:

  1. Custom circuit handler - Not working
  2. o.DisconnectedCircuitRetentionPeriod = TimeSpan.FromSeconds(0); - Not working

The only thing that seemed to work in diagnostics tool and in logging GC.GetTotalMemory(false), was to run GC.Collect() or GC.GetTotalMemory(true). But it did nothing in Kubernetes.

Why is the memory just climbing, and how do I stop the server from retaining circuits?

Thanks for any help in advance :)

Expected Behavior

No response

Steps To Reproduce

  1. Create a new Blazor Server-Side project
  2. Run the app and attatch a profiler to it
  3. Keep refreshing the page and watch the memory increase

Exceptions (if any)

No response

.NET Version

5.0.405

Anything else?

.NET SDK (reflecting any global.json): Version: 5.0.405 Commit: 63325e1c7d

Runtime Environment: OS Name: Windows OS Version: 10.0.19043 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\5.0.405\

Host (useful for support): Version: 5.0.14 Commit: d5b56c6327

.NET SDKs installed: 5.0.203 [C:\Program Files\dotnet\sdk] 5.0.400 [C:\Program Files\dotnet\sdk] 5.0.405 [C:\Program Files\dotnet\sdk]

.NET runtimes installed: Microsoft.AspNetCore.All 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All] Microsoft.AspNetCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 5.0.14 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.NETCore.App 5.0.14 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] Microsoft.WindowsDesktop.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App] Microsoft.WindowsDesktop.App 5.0.14 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

javiercn commented 2 years ago

@nzdvis thanks for contacting us.

You are measuring with a profiler and very likely in debug mode, which invalidates your measures.

You can check https://github.com/sebastienros/memoryleak for details on how to measure and detect memory leaks.

nzdvis commented 2 years ago

@nzdvis thanks for contacting us.

You are measuring with a profiler and very likely in debug mode, which invalidates your measures.

You can check https://github.com/sebastienros/memoryleak for details on how to measure and detect memory leaks.

Hello @javiercn,

Yes, I looked at that afterwards.

But I'm also measuring in production from the docker image I use in Kubernetes, where the memory usage also is constantly climbing. That's the most important part (The two blue screenshots).

javiercn commented 2 years ago

@nzdvis we keep a number of circuits (up to a max) in a disconnected state for about 3 minutes (this is the default but it is configurable) before they get "released". Even after they get released, the memory won't be claimed until the next GC happens. Even after the next GC happens, you might not see the memory decrease (depending on how you are measuring) if the GC doesn't return the memory to the OS.

Also, an important side note is that .NET 5.0 is out of support and we would recommend in any case to move to 6.0 as the first step

nzdvis commented 2 years ago

@javiercn and how is this configurable?

As I wrote, I have tried:

  1. Custom circuit handler - Not working
  2. o.DisconnectedCircuitRetentionPeriod = TimeSpan.FromSeconds(0); - Not working

But I'll look into moving to 6.0 soon.

Thanks for your help so far.

javiercn commented 2 years ago

@nzdvis it takes some time from when a user navigates away until we detect that the circuit was disconnected. Mostly because normally the browser abruptly terminates the connection and it takes SignalR some time to pick that up.

nzdvis commented 2 years ago

@javiercn my bad, I just forgot how browsers work :D

Thanks, closing "issue" now :)

javiercn commented 2 years ago

@nzdvis no worries. This is a confusing area for many people and we are looking to see how we can bring more visibility to it in the future.