如何使用Roslyn CSharpCompilation避免内存泄漏?

问题描述 投票:1回答:1

首先,我使用Windows 10与visual studio 2019使用.net core 3.1我使用Nuget的Roslyn Microsoft.Net.Compilers 3.4.0和Microsoft.CodeAnalysis 3.4.0。

我在我的项目中使用Roslyn来动态编译脚本。我注意到我的应用程序在编译一些非常小的脚本(5-10kb)时,内存占用率非常高(每个脚本占用20-50MB的内存)。

我最初以为内存的使用是来自于加载程序集,但我将其隔离开来。CSharpCompilation.Create 这似乎需要10MB,而 CSharpCompilation.Emit 把剩下的(10-40MB)。

我减少了它来重现这个bug

public byte[] CompileCSharpCode(string assemblyName, string code)
{
    SyntaxTree syntaxTree = SyntaxFactory.ParseSyntaxTree(code, null, "");
    CSharpCompilation compilation = CSharpCompilation.Create
    (
        assemblyName,
        new[] { syntaxTree },
        options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary),
        references: _referencesList
    );
    //at this point the memory usage goes up by 10MB
    using (var stream = new MemoryStream())
    {
        var emitResult = compilation.Emit(stream);
        //at this point the memory usage goes up by 10-40MB
        return stream.ToArray();
    }
}

我希望在调用函数、创建对象和编译时,内存会增加,但内存一直没有释放。在编译了200个脚本后,内存使用量达到了几GB。

即使我把编译时使用的所有对象,包括保存编译结果的字节数组都处理掉,内存也一直居高不下。

目前,我不得不创建第二个.net core应用程序,我调用它将每个脚本1个1个地预编译到.dll文件中,然后加载到内存中(200个脚本总共需要20MB的内存)。

有没有一种方法可以用Roslyn编译我的脚本,而不会出现这种巨大的内存问题?

c# memory-leaks roslyn
1个回答
1
投票

问题是Roslyn正在为你的编译创建和加载一个汇编,而且它从未被卸载。 使用.NET Core 3.0中新的可收集的AssemblyLoadContext功能,这样你就可以卸载它。 我写了 本文 来证明它。

© www.soinside.com 2019 - 2024. All rights reserved.