C# 收集动态程序集:在没有RunAndCollect的情况下,从一个程序集移动到多个模块和程序集会使内存使用量增加三倍

C# 收集动态程序集:在没有RunAndCollect的情况下,从一个程序集移动到多个模块和程序集会使内存使用量增加三倍,c#,reflection,clr,code-generation,.net-assembly,C#,Reflection,Clr,Code Generation,.net Assembly,在我们公司,我们有几种内部语言和编译器/反编译器,因此我们积极利用C动态代码生成和反射能力。我们编写的大多数代码只是在运行时动态创建代码,或者使用我们的专有脚本语言 在某一点上,我们发现向动态程序集添加类型会在^2上缩放,可能是因为整个程序集都被重写了?这意味着当创建了超过10k个类型时,我们的软件可能会变得更慢。我们当时所做的是保留一个动态程序集和模块,并在生成动态代码时向其添加类型,而DynamicMethods有几个例外 为了实现这一点,我们对类型、模块和程序集的最佳组合进行了梯度下降,以

在我们公司,我们有几种内部语言和编译器/反编译器,因此我们积极利用C动态代码生成和反射能力。我们编写的大多数代码只是在运行时动态创建代码,或者使用我们的专有脚本语言

在某一点上,我们发现向动态程序集添加类型会在^2上缩放,可能是因为整个程序集都被重写了?这意味着当创建了超过10k个类型时,我们的软件可能会变得更慢。我们当时所做的是保留一个动态程序集和模块,并在生成动态代码时向其添加类型,而DynamicMethods有几个例外

为了实现这一点,我们对类型、模块和程序集的最佳组合进行了梯度下降,以动态生成,从而提高性能

我们实现了一个抽象层,当我们创建动态类型时,它会根据结果显示的最佳方式根据需要自动创建模块/程序集。这具有预期的性能优势。这些程序集/模块/类型反射对象始终通过各种字典和散列集在幕后对它们进行强引用

然而,几个月后,一些非常奇怪的问题开始出现。第一次是非常间歇性的,每跑3/4次就会发生一次。这是致命的ExecutionEngineeException,错误代码为80131506。这是非常令人困惑的,我们最初认为这是由从.NET451升级到.NET472引起的。我们以前偶尔会遇到这个问题。最终,我们将System.Reflection.Emit.AssemblyBuilderAccess设置为RunAndCollect。当我们将此更改为“仅运行”时,我们再也没有遇到此问题。请记住,我们始终保持对这些程序集的强引用,因此对于如何解决问题,这是非常令人困惑的

然而,问题并没有止于此,当我们进一步深入.NET的深渊时,我们发现了无法形容的恐怖。看来我们的程序的内存使用量增加了三倍,而且很多程序都出现了内存不足的异常。通过限制程序的“强度”(一种减少内存使用的设置),我们的程序可以运行,但所需时间是原来的三倍

考虑到这种行为,我们似乎产生了太多的动态程序集,需要收集它们,否则就会耗尽内存。然而,我发现很难相信动态程序集会占用很多空间,而且我不知道如何收集它们,假设我们维护的对象是动态程序集中类型的实例,这些实例可能包含对类型对象的引用,并直接对这些动态程序集中的反射对象进行强引用

因此,我的问题是动态程序集集合在.NET framework中究竟是如何工作的,以及为什么我们要获得这些FatalExecutionEngine异常/OutOfMemory异常


我认为,您得到的致命错误代码80135106通常是由动态程序集中的循环类型引用引起的,因此程序集1包含引用程序集2中类型的类型-可能通过专用字段,但程序集2最终包含引用程序集1的类型。在收集程序集时,它很容易导致堆栈溢出


查看此链接以了解通过XAML发生此情况的实例。您是否可以澄清:这里的问题是什么?进行了编辑:因此,我的问题是动态程序集集合在.NET framework中究竟是如何工作的,以及为什么我们要获得这些FatalExecutionEngine异常/OutOfMemory异常?