c# - 如何使用 Roslyn CSharpCompilation 避免内存泄漏
问题描述
首先,我使用 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 的内存)来编译一些非常小的脚本(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 功能,以便您可以卸载它。我写这篇文章是为了证明这一点。
推荐阅读
- php - Symfony 日期到字符串的转换
- kotlin - Jetpack Compose @Composable 函数编译成什么?
- java - Java 创建带有参数和返回值的函数的 ArrayList
- java - Java/Spring 错误:“reactor.netty.http.server.HttpServer”中的“create()”不能应用于“(java.lang.String, int)”
- javascript - 有没有办法在 React.js 中使用这样的 JavaScript 文件?
- android - 如何使用来自服务器 NodeJS 的自定义消息而不是 Kotlin 的改造?Retrofit 用 OK 和 Conflict 改变消息
- node.js - 处理快递中的端口已在使用错误
- python - 导入熊猫在 Jupyter Notebook 中不起作用
- java - Kafka ProducerConfig 日志级别
- scala - 执行 dropDuplicates() 后,计数时得到不同的计数