预加载所有组件(JIT)

我们正在第一次加载一些重型UI屏幕。 我们的项目分为一个主要的可执行文件和几个DLL文件。 DLL文件还可以包含UI屏幕,这些屏幕在第一次加载时很慢。

有没有办法(在代码中)我们可以预加载所有引用的程序集,以避免JIT编译命中?

我知道有一种名为NGen的工具。 是否有可能在开发环境中运行NGen,以便我们可以立即看到它的影响? 但理想情况下,我们希望从代码中预加载引用的程序集。

使用C#.NET 3.5和DevExpress作为UI组件。

你有没有试过/看看这个 ?

也就是说,对于要预先JIT的每个程序集执行以下操作。

static void PreJIT() { foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) { foreach (var method in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle); } } } 

看看NGen吧 。 另一个选择是使用ILMerge将所有程序集合并为一个。 每当我使用ILMerge时,我都会添加一个post build命令,以便它自动发生。 另一种选择(未经测试)是,如果你不介意更长的启动时间,你可以在每个程序集的开头手动调用Assembly.Load()。

我个人发现将预抖动放在“程序”中有助于某个应用程序,但这是一个特定于具体情况的问题。

更重要的是, wal的答案中的代码在遇到抽象方法时会崩溃,因此添加了两行代码来跳过抽象方法。

 static Program() { foreach (var type in Assembly.GetExecutingAssembly().GetTypes()) { foreach (var method in type.GetMethods(BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)) { if ((method.Attributes & MethodAttributes.Abstract) == MethodAttributes.Abstract|| method.ContainsGenericParameters) { continue; } System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle); } } Console.WriteLine("jitted!"); } 

您可以只创建位于externall程序集中的类的实例。 只需在有限的范围内调用构造函数(我的意思是在函数内部声明变量。它不应该是全局变量因为它会延迟GC来处理该实例)。 这将加载程序集,编译它并缓存它。 您甚至可以在后台线程中执行此操作,以便主线程保持响应。

你可以在任何机器上使用NGen – 在CLR中没有“开发环境”的概念……当你使用它时确保实际使用了NGen的图像(参见Native Image Generator(Ngen.exe)的说明和外观对于文档中的FusLogVw注释)。

你也可以通过调用你期望运行的所有代码来预先JIT(如Davita建议的那样),但是你需要调用所有类的每个方法,这些方法并不完全实用。

您应该分析您的应用程序以查看实际花费的时间 – 它可能是从磁盘读取程序集,而不是JITing本身…您可以通过启动应用程序,查看表单,关闭应用程序并重复来粗略地看到它脚步。 如果第二次运行速度快得多,那么应用程序大部分时间都在从磁盘读取数据,而不是JITing。