缓解:新的 64 位 JIT 编译器

从 .NET Framework 4.6 开始,运行时包含用于实时编译的新 64 位 JIT 编译器。 此更改不会影响使用 32 位 JIT 编译器的编译。

意外行为或异常

在某些情况下,使用新的 64 位 JIT 编译器进行编译会导致运行时异常或执行由旧 64 位 JIT 编译器编译的代码时不观察到的行为。 已知差异如下:

重要

所有这些已知问题已在 .NET Framework 4.6.2 发布的新 64 位编译器中得到解决。 大多数也已在 Windows 更新随附的 .NET Framework 4.6 和 4.6.1 的服务版本中得到解决。 你可以通过确保 Windows 版本是最新的,或通过升级到 .NET Framework 4.6.2 来消除这些问题。

  • 在某些情况下,在启用优化的发布版本中,取消装箱操作可能会引发 NullReferenceException

  • 在某些情况下,在大型方法主体中执行生产代码可能会引发 StackOverflowException

  • 在某些情况下,传递给方法的结构被视为引用类型,而不是发布版本中的值类型。 此问题的表现形式之一是,集合中各个项的显示顺序出现异常。

  • 在某些情况下,如果启用了优化,无法正确比较 UInt16 值与其高位集。

  • 在某些情况下,尤其是在初始化数组值时,通过 OpCodes.Initblk IL 指令执行的内存初始化可能会使用不正确的值初始化内存。 这可能会导致未经处理的异常抛出或输出不正确。

  • 在某些极少数情况下,如果启用了编译器优化,条件位测试可能会返回错误的 Boolean 值或引发异常。

  • 在某些情况下,如果 if 语句用于在进入 try 块之前和从 try 块中退出之前测试条件,且在 catchfinally 块中计算的条件相同,那么新版 64 位实时编译器会在优化代码时从 ifcatch 块中删除 finally 条件。 因此,ifcatch 块中的 finally 语句代码会无条件地执行。

缓解已知问题

如果遇到上面列出的问题,可以通过执行下列任一操作来解决:

  • 升级到 .NET Framework 4.6.2。 .NET Framework 4.6.2 随附的新版 64 位编译器解决了上面列出的所有已知问题。

  • 运行 Windows 更新,以确保 Windows 是最新版本。 .NET Framework 4.6 和 4.6.1 服务更新可解决以上问题,取消装箱操作中的 NullReferenceException 除外。

  • 使用旧版 64 位 JIT 编译器进行编译。 请参阅其他问题的缓解措施部分,详细了解如何执行此操作。

缓解其他问题

如果遇到的是旧版和新版 64 位 JIT 编译器编译的代码的其他任何行为差异,或是使用新版 64 位 JIT 编译器编译的应用程序的调试和发布版本的其他任何行为差异,可以使用旧版 64 位 JIT 编译器编译应用程序,具体操作如下:

  • 根据应用程序,您可以将 <useLegacyJit> 元素添加到应用程序的配置文件中。 下面的代码禁用新版 64 位 JIT 编译器,改用旧版 64 位 JIT 编译器进行编译。

    <?xml version ="1.0"?>  
    <configuration>  
        <runtime>  
           <useLegacyJit enabled="1" />  
        </runtime>  
    </configuration>  
    
  • 对于每个用户,可以将名为 REG_DWORDuseLegacyJit 值添加到注册表的 HKEY_CURRENT_USER\SOFTWARE\Microsoft\.NETFramework 密钥中。 如果值为 1,可以启用旧版 64 位 JIT 编译器;如果值为 0,可以禁用旧版编译器,启用新版 64 位 JIT 编译器。

  • 对于每台计算机,可以将名为 REG_DWORDuseLegacyJit 值添加到注册表的 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework 密钥中。 如果值为 1,可以启用旧版 64 位 JIT 编译器;如果值为 0,可以禁用旧版编译器,启用新版 64 位 JIT 编译器。

还可以在 Microsoft Connect 上报告 bug,告诉我们你遇到的问题。

另请参阅