dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.05k stars 4.03k forks source link

Possible memory leak in CSharpCompiler #52217

Open dave-yotta opened 3 years ago

dave-yotta commented 3 years ago

Version Used: 3.4.0 Steps to Reproduce:

  1. Compile some scripts
  2. Make sure everything is cleaned with a collectable assemblyloadcontext that has Unload called, descope the CSharpCompilation
  3. Look at a memory dump - memory is still held by Microsoft.CodeAnalysis.* via pinned references.

Expected Behavior:

There are no pinned references or otherwise after compilation is completed, unlimited numbers of compilations can proceed in an application without leaking memory.

Actual Behavior:

After successive compilations, application runs out of memory. Example of some pinned references:

image image

I see no LoaderAllocator or LoaderAllocatorScout in the snapshot, so I do believe the call to Unload on the assemblyloadcontext has been completed:

image

Let me know if there is any specific data you want.

jmarolf commented 3 years ago

@dave-yotta can you please post the code you are using to call the scripting APIs? Scripting will hold onto previous submissions indefinitely in a "REPL-like" scenario where it keeps track of the previous submissions.

cc: @tmat

dave-yotta commented 3 years ago

One of these guys is used and descoped - IAssemblyLoader just deals with the collectable AssemblyLoadContext.

https://gist.github.com/dave-yotta/27c9ff6d9bacac73b79fe8c0987164ae

Not intentionally doing any "REPL-like" stuff. I saw those pinned refs while debugging on windows, I assume they will accumulate, but I couldn't get any real trend going in 30mins of trying (probabbly 30 or so compilations, tested as part of a larger process) - what happens in prod takes hours/days looking at the memory graph if we interpret it like this - still waiting for someone to get me a dump from a real machine (and its linux).

tmat commented 3 years ago

The code is not using Roslyn Scripting APIs. It's creating C# compilations directly.

dave-yotta commented 3 years ago

Let me know if there's anything you'd like me to look at - I need to check a dump with it running on Linux and I'm waiting for our infrastructure team to catch and dump the problem in the wild. Might be there's no issue with Roslyn here and those refs are expected (and something else is causing a leak) - if they are please let me know :)

dave-yotta commented 3 years ago

I've also noticed that there's a 2-3 second penalty on the first compilation - pinned refs could be related to that warmup and I'd argue I'd want to keep that cache. Also if you know a way to AOT or speed up the first compile (moving to out of process so the impact is higher with the different/shorter daemon lifecycles).

kunalspathak commented 3 years ago

I am noticing some memory leaks and trying to investigate where are they coming from. @dave-yotta - Which tool are you using for profiling? Looks good.

dave-yotta commented 3 years ago

hey @kunalspathak that's JetBrains dotMemory.