EXE を作るプロジェクトのデフォルトが Any CPU から x86 に変わった理由 - または Any CPU の本当の意味

Visual Studio 2010 では EXE を作るプロジェクトのデフォルトが Any CPU から x86 に変わります。また、DLL を作るプロジェクトは Any CPU のままです。これらの理由を説明している記事を見つけました。

AnyCPU Exes are usually more trouble than they're worth - Rick Byers

良い記事なのでかいつまんで勝手に訳してみます。だいぶはしょっているいいかげんな訳なので、できれば原文も読んでください。それと、訳についてアドバイスがもらえるとうれしいです。

勝手訳

AnyCPU Exes are usually more trouble than they're worth

AnyCPU EXE は通常、価値よりもトラブルのほうが多い

私は過去数ヶ月にわたってここ(と一部の顧客)の人々と「AnyCPU」(アーキテクチャ中立)のマネージ EXE のコスト/利点のトレードオフについて興味深い議論をしました。それはほとんどあなたが望むものではなく、そして Visual Studio のデフォルトであってはならないという合意に達したと思います。この話題が一部の人々の興味(そして、ショックさえ)を引くかもしれないので、この根拠を共有しようと思いました。

Background - .NET and 64-bit

背景 - .NET と64ビット

Win64(64ビットバージョンの Windows)によって PE ファイル(EXE と DLL)は32ビット「または」64ビットとマークできるようになりました。32ビット EXE は Win64 上では、プロセスに32ビットオペレーティングシステムの幻想を見せる「WOW(Windows32 on Windows64)」の中で走ります。通常、32ビット DLL は32ビットプロセスだけにロードでき、64ビット DLL は64ビットプロセスだけにロードできます。CLR2.0 で64ビットサポートを加えたとき、マネージバイナリは難しい CPU 依存がなかったので32ビットと64ビットのどちらでも使えるようにしました。私たちは人々に32ビットと64ビットの両方のプロセスから再利用できる .NET ライブラリを書くことができて欲しかったので、Windows の OS ローダーサポートを拡張してアーキテクチャ中立(AnyCPU)な PE ファイルを使用可能にしました。
マネージのアーキテクチャ中立 DLL は32ビットと64ビットのどちらのプロセスにもロードでき、正常に動きます。AnyCPU EXE は64ビット OS では(ldr64 が何か言わなければ)64ビットプロセスとして動き、32ビット OS では32ビットプロセスとして動きます。Visual Studio 2008 では AnyCPU が C#VB プロジェクトのデフォルトプラットフォームです。これはデフォルトであなたがコンパイルするアプリケーションが32ビット OS では32ビットプロセスとして、64ビット OS では64ビットプロセスとして動くことを意味します。これはすばらしいことで、確かにたいていうまくいきます。しかし、ちょっと不利な面がいくつかあります。

The costs of architecture-neutral EXEs

アーキテクチャ中立 EXE のコスト

AnyCPU が EXE のデフォルトであってはならないと考える理由がいくつかあります。誤解しないで欲しいのですが64ビットハードと OS は間違いなくよいものです。しかし、それが大部分のプロセスが64ビットでなければならないことを必ずしも意味するわけではありません。私が Visual Studio の EXE プロジェクトのデフォルトを x86 にすることを正当化するために、議論で使ったリストはこれです。


1. 2つの非常に異なるモードで動作することは、製品の複雑さとテストのコストを上げます

しばしば人々はアーキテクチャ中立アセンブリのネイティブインタロップの意味に気づいていません。それは、あなたが依存するネイティブ DLL の32ビットと64ビットバージョンが同じように利用できることを確実にする必要があることを意味します。そして適切なほうが自動的に選ばれます。OS の API を呼ぶのは WOW のおかげでとても簡単です。しかし、マネージアプリにネイティブ DLL を一緒に配布している人々は64ビットシステムで32ビット DLL が問題を起こすことにはじめは驚きます。また、マネージでは珍しいですがポインターサイズのバグ(IntPtr と Int32 のサイズを同じと仮定してしまったり、マーシャリングの宣言を誤るミス)もいまだにあります。
また、コードを二回テストしなければいけないという問題があります!すべてのプラットフォームでテストし、サポートするには大きなコストを払うことになります。


2. 32ビットはいずれにしろより速い傾向があります

アプリケーションが32ビットか64ビットモードで走るとき、32ビットモードのほうが少し速い傾向があります。大きなポインターは多くのメモリとキャッシュを消費します。そして利用できる CPU キャッシュのバイト数は32ビットと64ビットプロセスで同じです。もちろん WOW レイヤーは若干のオーバーヘッドを加えますが、私が見た大部分の現実のシナリオではネイティブ64ビットプロセスより WOW のほうが速いことを示しました。


3. いくつかの機能が64ビットでは利用できません

32ビットと64ビット間で完全に同じ機能にしたいのですが、現実はまだそうではありません。CLR v2 は混在モードデバッグx86 だけでサポートしました。そして、CLR v4 で x64 サポートを加えましたが、エディット&コンティニューや IntelliTrace はまだ x64 でサポートしていません。CLR チームで新しい機能を加えるときは、いつも x64 を第一級市民と考えています。しかし、現実は我々が複雑なコードベース(例えば完全に別々の32ビットと64ビット JIT コンパイラ)を持っており、トレードオフをしなければいけないということです。

So how is Visual Studio 2010 and .NET 4.0 changing?

それで Visual Studio 2010 と .NET 4.0 はどう変わりますか?

CLRコンパイラは何も変えていません。両方のモードをサポートし続けます。しかし、これらの問題を議論した後、VS プロジェクトシステムチームは、VS2010 で EXE プロジェクトのデフォルトを x86 にすることに同意しました。AnyCPU は DLL(どんなプロセスにロードされるか必ずしもわからない)ではまだすばらしい価値があり、AnyCPU をやめる十分な正当性はありません。そのため、DLL プロジェクトは AnyCPU のままです。
[訳注: ベータ1では誤って DLL も x86 になっていたらしい]
[訳注: DLL は32ビットと64ビットの両方のプロセスで使えるので、両方でテストが必要です]

この問題を議論したとき、ほとんどの人は x86 をデフォルトにすることは少なくとも数年間は最高の選択と同意しました。これは64ビット OS とフレームワークのサポートの減少を意味するものではありません[訳注:全体の半分くらいがこの点についてくどくど書いてありますが、ばっさり省きました。よっぽど言われたんだと思います]。

おまけ

ildasm で PE ヘッダを覗いて AnyCPU/x86/x64 を比べてみました。ia64?あー、聞こえない。

COFF Header の Machine Type は AnyCPU/x86I386(0x14c)。x64 は AMD64(0x8664)。
PE Optional Header のマジックナンバーは AnyCPU/x86 が 0x10b = 32bit(PE32)、x64 は 0x20b = 64bit(PE32+)。

CLR Header
AnyCPU .corflags 0x00000001 // ILONLY
x86 .corflags 0x00000003 // ILONLY 32BITREQUIRED
x64 .corflags 0x00000001 // ILONLY

AnyCPU の PE ファイルは見かけは32ビットの体裁をとっているようです。