c# - 如何使用 Roslyn CSharpCompilation 避免内存泄漏

标签 c# memory-leaks roslyn

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

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

我首先认为内存使用来自于加载程序集,但我隔离了 CSharpCompilation.Create,它似乎占用了 10MB,而 CSharpCompilation.Emit拿走其余的 (10-40MB)。

我减少了它以重现错误

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 核心应用程序,我调用它来预编译我写入 .dll 文件的每个脚本,并将它们加载到内存中(这 200 个脚本总共需要大约 20MB 的内存)

有没有办法用 Roslyn 编译我的脚本而不会出现这个巨大的内存问题?

最佳答案

问题是 Roslyn 正在为您的编译创建和加载一个程序集,但它永远不会被卸载。使用 .NET Core 3.0 的新的可收集 AssemblyLoadContext 功能,以便您可以卸载它。我写了this article来证明它。

关于c# - 如何使用 Roslyn CSharpCompilation 避免内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59597361/

相关文章:

c# - 使用 imageresizer 和 WicBuilder 时,水印无法显示在图像上

android - CardboardActivity 中的内存泄漏

ios - 如何快速避免 AFNetworking 导致的内存泄漏

c# - 如何使用 Roslyn 确定 XML 文档注释中 cref 的类型?

c# - 访问窗口 UWP C# 上的关闭按钮

c# - 如何在基于 token 的身份验证的 ASP.Net WebAPI 2.0 中使用 Swagger

c# - WCF-Ajax 启用的 Web 服务。部署时未定义服务

.net - 我应该在我的 WPF 应用程序中手动强制垃圾收集吗?

visual-studio - 如何在 VS 2022 中调试 Roslyn 源代码生成器?

c# - 运行 Roslyn 脚本时在运行时找不到程序集