-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Every CSharpScript.EvaluateAsync() call generates a new assembly that does not get unloaded #41722
Comments
Unloading is currently not supported. |
Possibly related to #2621 |
I think this is also related to #42134 @tmat Is there any plans to support unloading the assembly? This really defeats the purpose of having a dynamic code execution system. Exposing an a handle to allow the user to unload the assembly when they know they are finished with it sounds like the most logical approach. |
@jasekiw We would accept a contribution that would add this capability on .NET Core. |
I would love to contribute this functionality. However, I have some obligations I have to look after for the time being so it might take some time before I can fully dig in. Do you have any recommendations of material to read (other than the contributing guide) that can help familiarize myself with the concepts used in the scripting api codebase? I assume that this namespace (https://github.com/dotnet/roslyn/tree/master/src/Scripting/Core/Hosting/AssemblyLoader) is that namespace I need to be paying attention to, am I correct in that assumption? Thanks! |
Same here. CSharpScript.EvaluateAsync effectively causes a memory leak every time it is used. We are resorting to caching scripts from CSharpScript.Create and maybe event this suggestion #22219 (comment) Am I missing something? How to execute C# scripts without memory leak? |
I think another way for this is to generate overloads to And then have Roslyn just use those passed in contexts. But for the cases of people using Roslyn Scripting with .NET Framework I would suggest that for .NET Framework to replace Then this can solve the problem entirely. But then it would possibly cause another issue: the generated code would have to load the assemblies they depend on from the program's directory of the program's assembly itself, and then look in the GAC (Global Assembly Cache) for the other assemblies the scripts might depend on. |
For what it's worth, I was able to overcome this hurdle by off-loading the compilation and execution to a separate assembly and executing the necessary functions from a different domain context. It should be noted that my specific needs were rather particular. I am allowing the user to essentially specify the guts of a function that takes some dynamic objects, calculates a value, and returns a double as a result. However, someone may be able to take my approach and make it more generic still.
I'm able to make use of it without a memory leak by loading the assembly into a separate app domain, executing the code, and then unloading the app domain.
|
I may be wrong from my somewhat naïve viewpoint, but I believe a part of the issue is that the |
I agree, perhaps it should default to them being collectible so that way there would be a call to |
Just adding on in hopes this will get addressed. This makes the feature unusable for our needs. I need to execute scripts repeatedly based on dynamic conditions. |
Currently I think the only other way to bypass this is to have the code that calls the scripting apis itself be in it's own colletible ALC and hope it uses the "current ALC" for it which would be the ALC that the scripting apis were called in. |
At least until oneone makes a patch to their LoadContext |
Has this issue been fixed? I've been using a delegate as it seems it doesn't hold compilation resources:
Not sure if this is safe but I also tried:
In an attempt to get GC to free resources, however I'm not sure how to test the effectiveness of this, maybe someone can help clarify. |
I faced with same issue, rather using CSharpScript, I created new compilation and custom AssemblyLoadContext with Collectible. var syntaxTree = CSharpSyntaxTree.ParseText(sourceCodeSb.ToString());
var compilation = CSharpCompilation.Create("GeneratedExpressionAssembly", new List<SyntaxTree>() { syntaxTree })
.WithReferences(assemblies)
.WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
var emitResult = compilation.Emit(ms);
ms.Seek(0, SeekOrigin.Begin);
var alc = new CustomAssemblyLoadContext();
var assembly = alc.LoadFromStream(ms);
var assemblyType = assembly.GetType("GeneratedExpressionClass");
alc.Unload();
return assemblyType;
} |
Honestly I feel like an overload of the roslyn scripting apis would be a safer option. |
Just chiming in that I very nearly sent this to production for a long lived API instance, that would have been a nightmare to debug. If this API is going to effectively leak memory on every call there really needs to be a big giant warning about it at least here https://github.com/dotnet/roslyn/blob/main/docs/wiki/Scripting-API-Samples.md and probably also in the library doc comment for the function. ... or just fix it/provide a safe endpoint that's as easy to use but that doesn't seem likely given the number issues and how they've been open around this. |
How? |
Using the following code:
Output:
The scripting API generates a new assembly for every call that does not get unloaded, resulting in an ever-increasing number of loaded assemblies and thus in an increasing amount of memory consumption.
There does not appear to be a way to unload the generated assemblies since they are not collectible (How to use and debug assembly unloadability in .NET Core).
How can we unload these generated assemblies?
The text was updated successfully, but these errors were encountered: