.NET Framework 配置与 NGen 工具使用指南
1. .NET Framework 配置工具
在使用 .NET Framework 时,我们可以借助 MMC(Microsoft Management Console)这一可插入式软件组件来完成大部分管理任务。不过要注意,该工具仅适用于 Microsoft Windows NT、Windows 2000、Windows XP 和 Windows Server 2003 系统。
要启动 Microsoft .NET Framework 配置工具,可按以下步骤操作:
1. 点击“开始”菜单。
2. 选择“控制面板”。
3. 点击“管理工具”。
若要交互式修改应用程序的配置文件,可按以下流程操作:
1. 右键点击“应用程序”元素,选择“添加”命令,将应用程序添加到已配置应用程序列表中。
2. 右键点击应用程序元素,选择“属性”命令,会弹出一个对话框,可在其中修改应用程序配置文件的重要参数。
3. 展开应用程序元素,右键点击“已配置程序集”文件夹,选择“添加”,可将新的程序集添加到应用程序需要重定向的列表中。点击“完成”后,会出现一个窗口,在这里可以指定版本重定向的方式以及每个版本程序集对应的代码库。
2. NGen 工具概述
在 .NET 运行时中,通常会在首次执行方法前将 IL 代码编译为本地代码,这一过程被称为 JIT(Just-In-Time)编译。JIT 编译有诸多优点,比如能为目标处理器生成优化的操作码序列、优化间接方法调用等。然而,它也存在一些缺点,例如会减慢应用程序的启动速度,且在程序运行时进行编译,无法对整个 IL 代码进行全局优化。
为解决这些问题,.NET Framework 提供了 NGen 工具,它可以将整个程序集转换为本地代码,且只进行一次编译,能显著减少应用程序的启动时间。但需要注意的是,NGen 不能在开发系统上编译应用程序后将本地代码可执行文件移到客户端计算机,必须在目标计算机安装应用程序后进行编译,并且包含 IL 代码的程序集必须存在才能正常执行。同时,NGen 无法防止程序集被反编译,微软自身也使用 NGen 预编译 .NET Framework 的一些程序集,这也是 .NET Framework 安装时间较长的部分原因。
NGen 工具会将应用程序的程序集编译后,把本地代码的映像存储在“C:\Windows\Assembly”文件夹下的“本地映像缓存”中。.NET 会自动选择本地代码映像执行,但前提是其版本要与应使用的 IL 映像对应。如果重新编译原始程序集,也需要使用 NGen 重新编译,否则本地代码版本只会占用磁盘空间。而且,如果依赖的程序集被重新编译,本地代码映像也会过时,此时 .NET 会使用 IL 版本且不会给出错误信息,这也是 NGen 在早期不受 .NET 开发者欢迎的原因。
3. .NET Framework 2.0 中 NGen 的新特性
- 预编译应用程序 :当预编译应用程序(而非 DLL 库)时,NGen 会为应用程序及其所有依赖的程序集创建本地代码映像。
- 自动重新编译 :如果应用程序或其依赖项更新,NGen 会自动重新编译应用程序及其所有依赖项。这是因为 .NET Framework 2.0 安装了一个名为 .NET Runtime Optimization Service 的 Windows 服务,它会在后台检查使用 NGen 编译的应用程序是否需要重新编译。该服务在系统空闲时运行,也可以强制其执行所有待处理任务。
- 依赖程序集定位 :NGen 定位依赖程序集的逻辑与运行时的 CLR 一致,能保证使用合适版本的依赖程序集,避免了 .NET Framework 1.1 中 NGen 和 CLR 逻辑不一致的问题。
- 程序集共享 :可以在一个进程的多个应用程序域之间共享使用 NGen 编译的程序集,这一改进使得在 ASP.NET 应用程序中也能体现预编译程序集的优势。
4. NGen 工具的使用
在 .NET Framework 2.0 中,NGen 的语法有所变化,但旧语法仍被支持。新语法中,在第一个参数指定 NGen 命令,以下是一些常见命令及使用示例:
-
INSTALL 命令
:生成指定可执行文件(根可执行文件)及其所有依赖程序集的本地代码映像。
- 对于普通可执行文件:
NGEN INSTALL myapp.exe
- 若程序集在 GAC 中,需指定强名称:
NGEN INSTALL "myapp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ab349f12fe3a234e, ProcessorArchitecture=x86"
- 默认情况下,NGen 会编译主应用程序及其所有依赖项。若要限制编译的依赖程序集数量,可使用
/NODEPENDENCIES
选项:
NGEN INSTALL myapp.exe /NODEPENDENCIES
-
UNINSTALL 命令
:删除与根可执行文件及其所有依赖程序集相关的所有本地代码映像(除非其他使用 NGen 编译的应用程序仍在使用)。
- 对于普通可执行文件:
NGEN UNINSTALL MyApp.exe
- 也可以指定强名称,若省略某些元素,如
Culture
属性,NGen 会卸载所有同名程序集;若只提供程序集名称,则会删除该程序集的所有本地代码映像。
-
UPDATE 命令
:指示 NGen 重新编译所有需要更新的本地代码映像,即自上次调用命令后更新的程序集或依赖于更新程序集的映像。
NGEN UPDATE
-
DISPLAY 命令
:列出本地映像缓存中的元素,分为根程序集和所有本地映像两部分。
- 可指定程序集名称或路径来限制输出:
NGEN DISPLAY c:\myapp.exe
或
NGEN DISPLAY System
5. NGen 服务
部分 NGen 命令支持
/QUEUE
开关,可通过 .NET Runtime Optimization 服务计划命令的后续执行。该服务不会随 Windows 自动启动,而是在调用排队命令时间接启动,队列清空后服务会变为非活动状态。默认情况下,服务仅在系统空闲时运行,不过可以为特定命令分配更高优先级并要求服务执行所有待处理命令。
-
异步生成本地代码映像
:在
INSTALL
命令中添加
/QUEUE
选项:
NGEN INSTALL myapp.exe /QUEUE
-
指定优先级
:
/QUEUE
开关后可跟 1 到 3 的优先级索引,1 为最高优先级(默认值为 3)。优先级为 1 或 2 的命令无需等待系统空闲即可执行:
NGEN INSTALL myapp.exe /QUEUE:1
-
系统级更新计划
:在
UPDATE
命令中应用
/QUEUE
选项:
NGEN UPDATE /QUEUE
-
查看排队命令
:
NGEN QUEUE STATUS
-
暂停和恢复服务
:使用
PAUSE
命令及其子命令,例如为避免冲突,在后台编译多个程序集前暂停服务:
NGEN QUEUE PAUSE
NGEN INSTALL myapp.exe /QUEUE
NGEN INSTALL myapp2.exe /QUEUE
...
NGEN QUEUE CONTINUE
-
强制执行待处理重新编译
:
EXECUTEQUEUEDITEMS命令可选择指定 1 到 3 的优先级,若省略优先级,命令会在所有待处理重新编译执行完毕后返回:NGEN EXECUTEQUEUEDITEMS 1
6. 本地代码映像调试
如果要调试本地代码版本,可在
INSTALL
命令中使用
/DEBUG
开关,该选项会指示 NGen 生成调试符号和调试器所需的一切。若省略此开关而尝试调试程序集,则需使用 IL 映像。
NGEN INSTALL MyApp.exe /DEBUG
还可以指定
/PROFILE
选项生成可在性能分析器中执行的本地代码映像:
NGEN INSTALL MyApp.exe /PROFILE
本地映像缓存中会同时包含使用和未使用该开关编译的版本,无需使用不同参数执行 NGen 来测试调试和新版本。可使用
FUSLOGVW
实用工具验证是否使用了 DLL 本地代码映像的版本,因为它有专门用于本地映像的日志类别。
在编译最终会使用 NGen 编译的 DLL 时,在“高级编译设置”对话框中选择合适的基地址非常关键。理想情况下,应用程序使用的所有托管和本地 DLL 应具有不同的基地址,且地址间距要足够大,以便操作系统能在基地址加载 DLL。若无法在基地址加载 DLL,Windows 操作系统需要重新定义其基地址,这一过程较慢,且多个进程无法共享重新定义基地址的 DLL,会导致内存使用不优化。可使用
DUMPBIN
工具验证任何 DLL 的基地址。
7. NGen 工具的属性控制
7.1 独立于域的程序集
独立于域的程序集可以在一个进程的多个应用程序域之间共享,它只进行一次 JIT 编译,即使多个应用程序域使用也只占用固定的内存量,有助于提高性能,例如
mscorlib
始终作为独立于域的程序集加载。
不过,独立于域的程序集也有缺点,它不会从内存中卸载,且访问静态字段时需要通过间接寻址,因为 CLR 要确保每个应用程序域能看到自己的静态字段集。
要让应用程序加载独立于域的程序集,可在
Sub Main
方法中添加
LoaderOptimization
属性:
<LoaderOptimization(LoaderOptimization.MultiDomain)> _
Sub Main()
…
End Sub
LoaderOptimization
属性的参数有三个值:
-
LoaderOptimization.SingleDomain
:程序集针对应用程序域进行优化,除
mscorlib
外不会加载独立于域的程序集,这是默认参数。
-
LoaderOptimization.MultiDomain
:程序集优化为可在同一应用程序的多个应用程序域之间共享,可加载独立于域的程序集。
-
LoaderOptimization.MultiDomainHost
:程序集优化为可在多个应用程序域之间共享,这些应用程序域不一定运行相同的应用程序,可从 GAC 以独立于域的模式加载具有强名称的程序集,这是 ASP.NET 使用的参数。
需要注意的是,该属性只是程序集加载器的一个指示,运行时可能会根据情况忽略请求的优化,以默认模式加载程序集。
7.2 物理绑定
物理绑定是 NGen 工具的一项功能,能提高性能并减少本地代码映像使用的内存量(工作空间)。当应用程序运行时加载大部分或所有依赖程序集时,物理绑定特别有用。应用程序与一个或多个依赖程序集存在物理绑定时,所有这些程序集的本地代码映像会在应用程序启动时加载,但可能会增加启动时间并使本地代码映像的优化效果不明显。
可以使用
DependencyAttribute
和
DefaultDependencyAttribute
两个属性控制应用程序对依赖程序集的物理绑定:
' (在主应用程序中...)
' 始终加载 MathFunctions 程序集
<Assembly: Dependency("MathFunctions", LoadHint.Always)>
' 有时加载 FinancialFunctions 程序集
<Assembly: Dependency("FinancialFunctions", LoadHint.Sometimes)>
' 使用默认加载指示符加载 StringFunctions 程序集
<Assembly: Dependency("StringFunctions", LoadHint.Default)>
' (在 StringFunction 程序集中...)
' 该程序集最好始终由客户端加载
<Assembly: DefaultDependency(LoadHint.Always)>
物理绑定更适用于应用程序最可能加载的程序集,但要记住
Dependency
属性只是一个指示,NGen 可能会选择忽略它。
综上所述,NGen 工具在优化 .NET 应用程序性能方面有很大的潜力,但在使用过程中需要注意各种细节和限制,结合其新特性和属性控制,能更好地发挥其优势。
.NET Framework 配置与 NGen 工具使用指南
8. NGen 工具命令总结
为了更清晰地了解 NGen 工具的使用,下面将常见命令进行总结,形成一个表格,方便大家查阅:
| 命令 | 作用 | 示例 |
| — | — | — |
| INSTALL | 生成指定可执行文件及其所有依赖程序集的本地代码映像 |
NGEN INSTALL myapp.exe
NGEN INSTALL "myapp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ab349f12fe3a234e, ProcessorArchitecture=x86"
NGEN INSTALL myapp.exe /NODEPENDENCIES
|
| UNINSTALL | 删除与根可执行文件及其所有依赖程序集相关的所有本地代码映像 |
NGEN UNINSTALL MyApp.exe
|
| UPDATE | 指示 NGen 重新编译所有需要更新的本地代码映像 |
NGEN UPDATE
|
| DISPLAY | 列出本地映像缓存中的元素 |
NGEN DISPLAY c:\myapp.exe
NGEN DISPLAY System
|
| QUEUE STATUS | 查看排队命令 |
NGEN QUEUE STATUS
|
| QUEUE PAUSE | 暂停服务 |
NGEN QUEUE PAUSE
|
| QUEUE CONTINUE | 恢复服务 |
NGEN QUEUE CONTINUE
|
| EXECUTEQUEUEDITEMS | 强制执行待处理重新编译 |
NGEN EXECUTEQUEUEDITEMS 1
|
9. NGen 工具使用流程梳理
下面通过一个 mermaid 格式的流程图来梳理使用 NGen 工具的一般流程:
graph LR
A[选择操作] --> B{安装本地代码映像}
A --> C{卸载本地代码映像}
A --> D{更新本地代码映像}
A --> E{显示本地映像缓存信息}
B --> B1{普通可执行文件}
B --> B2{GAC 中的程序集}
B1 --> B11[/输入 NGEN INSTALL myapp.exe/]
B2 --> B21[/输入 NGEN INSTALL 强名称/]
C --> C1[/输入 NGEN UNINSTALL 可执行文件名/]
D --> D1[/输入 NGEN UPDATE/]
E --> E1{指定程序集}
E --> E2{不指定程序集}
E1 --> E11[/输入 NGEN DISPLAY 程序集名称或路径/]
E2 --> E21[/输入 NGEN DISPLAY/]
10. 常见问题及解决办法
在使用 NGen 工具的过程中,可能会遇到一些问题,下面为大家列举一些常见问题及对应的解决办法:
-
问题 1:本地代码映像版本与 IL 映像不匹配
-
现象
:重新编译原始程序集后,未使用 NGen 重新编译,导致本地代码版本占用磁盘空间且无法正常使用。
-
解决办法
:使用
UPDATE
命令让 NGen 重新编译所有需要更新的本地代码映像,即
NGEN UPDATE
。
-
问题 2:依赖程序集更新后,应用程序未重新编译
-
现象
:应用程序依赖的程序集被重新编译,但应用程序没有自动重新编译,仍使用旧的本地代码映像或 IL 版本。
-
解决办法
:确保 .NET Runtime Optimization Service 服务正常运行,它会在后台检查使用 NGen 编译的应用程序是否需要重新编译。也可以手动使用
UPDATE
命令或在
UPDATE
命令中添加
/QUEUE
选项进行系统级更新计划,如
NGEN UPDATE /QUEUE
。
-
问题 3:无法在基地址加载 DLL
-
现象
:在“高级编译设置”对话框中未选择合适的基地址,导致 Windows 操作系统需要重新定义 DLL 的基地址,出现加载慢和内存使用不优化的问题。
-
解决办法
:在“高级编译设置”对话框中为应用程序使用的所有托管和本地 DLL 选择不同且间距足够大的基地址,可使用
DUMPBIN
工具验证 DLL 的基地址。
11. 最佳实践建议
为了更好地使用 NGen 工具优化 .NET 应用程序性能,以下是一些最佳实践建议:
-
合理使用独立于域的程序集
:对于经常在多个应用程序域之间共享的程序集,如
mscorlib
,可以考虑将其设置为独立于域的程序集,通过在
Sub Main
方法中添加
LoaderOptimization
属性来实现。但要注意其不能从内存中卸载和访问静态字段需间接寻址的缺点。
-
谨慎使用物理绑定
:在应用程序运行时加载大部分或所有依赖程序集时,使用物理绑定可以提高性能和减少内存使用。但要注意可能会增加启动时间,可根据实际情况使用
DependencyAttribute
和
DefaultDependencyAttribute
属性来控制。
-
定期更新本地代码映像
:使用
UPDATE
命令或结合
/QUEUE
选项定期更新本地代码映像,确保其与最新的程序集版本保持一致。
-
调试时使用正确的选项
:在调试本地代码版本时,使用
/DEBUG
开关生成调试符号;在进行性能分析时,使用
/PROFILE
选项生成可在性能分析器中执行的本地代码映像。
12. 总结
NGen 工具为 .NET 应用程序的性能优化提供了强大的支持。通过将程序集编译为本地代码映像,减少了 JIT 编译带来的启动时间长和全局优化不足的问题。.NET Framework 2.0 中 NGen 的新特性,如预编译应用程序、自动重新编译、依赖程序集定位和程序集共享等,进一步提升了其功能和实用性。
同时,我们也需要注意 NGen 工具的使用细节和限制,如本地代码映像与 IL 映像的版本匹配、依赖程序集更新后的重新编译、DLL 基地址的选择等。通过合理使用 NGen 工具的属性控制,如独立于域的程序集和物理绑定,结合最佳实践建议,能够更好地发挥 NGen 工具的优势,提高 .NET 应用程序的性能和用户体验。
1697

被折叠的 条评论
为什么被折叠?



