在我们测试平台上发布客户端组件,经常会碰到因为build的版本是x86还是anycpu而引起的application error的问题。借此,研究了一下X86,X64,AnyCPU的区别。
使用.net平台自带的工具CorFlags的可以查看组件详细版本信息。下图比较了3种编译配置得到的组件的CLR头信息:
anycpu |
x86 |
x64 |
Collapse | Copy Code Version : v4.0.30319 CLR Header: 2.5 PE : PE32 CorFlags : 1 ILONLY : 1 32BIT : 0 Signed : 0 |
Collapse | Copy Code Version : v4.0.30319 CLR Header: 2.5 PE : PE32 CorFlags : 3 ILONLY : 1 32BIT : 1 Signed : 0 |
Collapse | Copy Code Version : v4.0.30319 CLR Header: 2.5 PE : PE32+ CorFlags : 1 ILONLY : 1 32BIT : 0 Signed : 0 |
留意2个比较重要的参数:PE, 32BIT
PE: PE32能够在32位和64位OS上运行, PE32+ 只能够在64位的OS上运行。
32BIT: 1表示只能在32位的CLR版本上运行,当然0表示可以在32/64位的CLR上运行。
结论:
在 64位 Windows OS上:
用 x86编译的程序集将在 WOW64 下运行的 32 位 CLR 上执行。
用 x64编译的程序集将在 64 位 CLR 上执行。
用 anycpu 编译的可执行文件将在 64 位 CLR 上执行。
用 anycpu编译的 DLL 将在与加载它的进程相同的 CLR 上执行。
在 32位 Windows OS上:
用 x86或anycpu 编译的程序集将在 32 位 CLR 上执行。
用 x64 编译的程序集无法运行。
那为什么我们往测试版上发布的一些客户端dll会造成错误呢?要看看我们的启动程序(可执行exe)到底是什么版本,x86呢还是anycpu.比较了以下production和Dev的客户端,结果如下:
Production版本的exe
Dev版本的exe
由于Dev版本的exe是anycpu版本的,所以在OS是64位的情况下,使用的是64位的CLR,
而此时如果它要加载的客户端dll是x86版本的只能在32位版本的CLR下运行,所以就会报错。
相反,production版本的exe是x86的,所以使用的是WOW64 下运行的 32 位 CLR,而此时,
不管它要加载的客户端dll是x86还是anycpu的,都不会有问题,因为用 anycpu编译的 DLL可以再任何版本的CLR运行。
所以,究其原因,是我们在打包client组件的时候,使用的是anycpu,而不是像production那样使用x86的原因。