2

我正在从事的项目将为大量类生成代码——预计会有数百到数千个。在生成时不知道这些类中有多少会被实际访问。

生成的类可以 (1) 全部存在于单个程序集(或可能是少数程序集)中,当脚趾消耗过程开始时将加载该程序集。

...或者 (2) 我可以为每个类生成一个程序集,就像 Java 将每个类编译为一个*.class二进制文件一样,然后提出一种机制来按需加载程序集。

问题:哪种情况会产生更好的(内存和时间)性能?

我的直觉是,对于案例 (1),加载时间和使用的内存与构成单个整体程序集的类的数量成正比。OTOH,案例 (2) 有其并发症。

如果您知道有关加载程序集内部的任何资源,尤其是调用了哪些代码(如果有的话!?)以及分配了哪些内存(新加载程序集的簿记),请分享它们。

4

2 回答 2

9

您正在尝试解决一个不存在的问题,程序集加载在 .NET 中得到了极大的优化

毫无疑问,将一个大型组件分解为许多较小的组件是您能做的最糟糕的事情。到目前为止,加载程序集的最大开销是查找文件。这是一个冷启动问题,CLR 加载程序被慢速磁盘所困,需要检索和搜索目录条目以定位包含文件内容的磁盘扇区。当可以从文件系统缓存中检索程序集数据时,此问题会在热启动时消失。请注意,Java 也不是这样做的,它会将 .class 文件打包到 .jar 中。.jar 大致相当于一个程序集。

找到文件后,.NET 使用操作系统工具使实际加载程序集数据变得非常便宜。它使用内存映射文件。这仅涉及为文件保留虚拟内存,而不是从文件中读取。

读取直到稍后才会发生,并且是由page fault完成的。任何按需分页虚拟内存操作系统的功能。访问虚拟内存会产生页面错误,操作系统从文件中加载数据并将虚拟内存页面映射到 RAM。之后程序继续,永远不会意识到它被操作系统打断了。产生这些页面错误的将是抖动,它访问程序集中的元数据表以定位方法的 IL。然后它从中生成可执行的机器代码。

此方案的一个自动好处是您永远不会为程序集中但未使用的代码付费。抖动根本没有理由查看包含 IL 的文件部分,因此它实际上从未被读取。

并注意这种方案的缺点,第一次使用一个类确实会因为磁盘读取而导致性能命中。这需要以一种或另一种方式支付,在 .NET 中,债务应在最后一刻到期。这就是为什么属性以缓慢着称的原因。

较大的组件总是比许多较小的组件好。

于 2012-11-16T16:10:01.370 回答
2

哪种情况会产生更好的(内存和时间)性能

考虑到编译器会为你做很多优化,选项 1 绝对是要走的路。每个类都有一个单独的程序集似乎完全是矫枉过正。不仅如此,您可能会发现加载 1 个大型程序集比加载许多小型程序集更快。

此外,这确实感觉像是过早的优化,我的建议是坚持第一个(理智的)选项,如果您认为需要,稍后将类拆分为单独的程序集。

于 2012-11-16T14:06:56.503 回答