Mono 2.4のコンポーネント
Mono 2.4を構成するコンポーネントは、次の3つのグループに分かれます。
- コアコンポーネント
- Mono/Linux/GNOME開発スタック
- Microsoft互換スタック
コアコンポーネントには、C#コンパイラ、仮想マシン、基底クラスライブラリが含まれます。これらのコンポーネントはEcma-334およびEcma-335規格に基づいているので、Monoは規格に準拠したフリーおよびオープンソースのCLI仮想マシンを提供できます。
Mono/Linux/GNOME開発スタックは、以下に示すようなGNOMEやフリーおよびオープンソースの既存ライブラリを活用することで、アプリケーション開発用の各種ツールを提供します。
- GUI開発用のGtk#
- Geckoレンダリングエンジンを利用するためのMozillaライブラリ
- UNIX統合ライブラリ
- データベース接続ライブラリ
- セキュリティスタック
- XMLスキーマ言語RelaxNG
Gtk#を利用すれば、MonoアプリケーションをネイティブアプリケーションとしてGNOMEデスクトップに組み込むことができます。データベース接続ライブラリは、MySQL、SQLite、PostgreSQL、Firebird、Open Database Connectivity(ODBC)、Microsoft SQL Server(MSSQL)、Oracle、オブジェクト関係データベースdb4oなど、多くのデータベースへの接続を可能にします。データベースコンポーネントの開発状況はMonoプロジェクトのWebサイトで公開されています。
Microsoft互換スタックは、Windows .NETアプリケーションをLinuxに移植する際に使用されます。このグループのコンポーネントには、ADO.NET、ASP.NET、Windows Formsなどが含まれます。これらのコンポーネントはECMA規格ではカバーされておらず、なかにはまだ特許で保護されているものもあります。
C#コンパイラ
Mono C#コンパイラ(MCS)は、C#のバージョン1.0、2.0、3.0に関しては機能的に完成されたものと見なされています。このコンパイラは、コンパイラそれ自身も含め、多くのC#プログラムをコンパイルできます。約400万行のC#コードから成るMonoや、その他いくつかのプロジェクトのコンパイルでも日常的に使われています。これはかなり高速なコンパイラで、IBM ThinkPad T40の場合、1秒あたり18,000行のC#コードをコンパイルできます。また、Mono.Sharp.dllアセンブリのMono.CSharp.Evaluatorクラスを使用すれば、このコンパイラをサービスとして利用することもできます。Mono 2.6からは、新しいコンパイラであるdmcsがC# 4.0のプレビュー版(C# 4.0の確定前にMono 2.6がリリースされるため)として利用できるようになります。
前ページのコメントのとおり、Mono 2.6はリリース済みです。
C#コンパイラは、定数のたたみ込み(C#言語仕様では必須)やデッドコードの削除など、入力の時点でいくつかの簡単な最適化を実行します。ただし、巻き上げ(hoisting)のような興味深い他の最適化はまだ実行できません。これは、現時点ではコンパイラによる出力時に基本的なブロック演算の実行に適した中間表現が生成されないからです。
中間層を追加して基本ブロック演算を可能にすることは難しくないはずですが、Monoの開発チームが目指しているのは汎用的なCILオプティマイザです。基本的なブロックベースの最適化を実行するために必要な情報はすべてCILレベルで利用できることから、Monoチームはこのステップを省略し、MCSで生成されたプログラムだけでなく任意のCILプログラムで巻き上げを実行できる汎用のCILオプティマイザを用意していると思われます。
この汎用CILオプティマイザがさらに拡張されて、定数のたたみ込み(すでにこの機能があるMCSでは不要)やデッドコードの削除が実行可能になれば、他のコンパイラ作成者も自らのプロジェクトでこのツールを使うことで、実稼働用のコンパイラを別途開発せずに済むようになる可能性があります。
Monoランタイム
Monoランタイムエンジンは、JITコンパイラ、Ahead-of-Time(AOT)コンパイラ、ライブラリローダ、ガベージコレクタ(Boehmによる保守的ガベージコレクタ)、スレッディングシステム、相互運用機能を備えています。Monoランタイムは、スタンドアロンのプロセスとして使用することも、アプリケーションに組み込むこともできます。
Monoランタイムを組み込めば、既存のCおよびC++コードのすべてを再利用しながらアプリケーションをC#で拡張することができます。
コンパイルエンジン
JITコンパイラの書き直しによって、これまではなかったいくつかの機能がサポートされるようになりました。その代表例がAOTコンパイル、簡単な移植、コンパイラ最適化のための確固たる基盤などです。AOTコンパイルのねらいは、起動時間短縮のためにネイティブコードへの事前コンパイルを行ったり、実行時にJITコンパイラで使用されるワーキングセットのコンパイルを行ったりすることです。システムにアセンブリ(Mono/.NETの実行可能ファイル)がインストールされていれば、コードを事前にコンパイルしたり、ソフトウェアのインストール先のCPUに合わせてJITコンパイラに生成コードのチューニングを行わせたりすることが可能です。.NETの世界では、こうした作業をngen.exeというツールで行います。
MonoのAOTコンパイラによって生成されるコードは位置独立コード(Position Independent Code:PIC)なので、普通にJITコンパイルされたコードよりも実行速度が若干遅くなる傾向があります。ただし、パフォーマンスが低下する代わりに、用意されている最適化の手法をすべて使用することができます。
バンドル
Monoはバンドルにも対応しています。バンドルにより、アプリケーションとそこで使用されるライブラリ、さらにMonoランタイムが1つの実行可能イメージにマージされます。バンドルは、アプリケーション内への「Monoの静的なリンク」と見なせます。
コード最適化のためのプラットフォーム
Monoチームとしては、Mono VMをJITコンパイラとして使用するだけでなく、Monoによるコード生成をできるだけ効率の高いものにする必要があります。そうした設計には、高、中、低のそれぞれのレベルの中間表現に対して適切に機能する最適化など、さまざまなレベルでの最適化が可能な優れたアーキテクチャが求められます。
また、それらの最適化のオン/オフを条件によって切り替えられるようにする必要もあります。JITコンパイルでは時間がかかりすぎて使えない最適化でも、AOTコンパイルのときや、プロファイルガイドを併用して実行メソッドのサブセットに対して適用する場合にはオンにできるからです。
ガベージコレクション
現在、MonoではガベージコレクションエンジンとしてBoehmのガベージコレクタ(GC)を使用しています。その一方で、Mono開発チームはMonoに特化した高精度なコンパクト化GCエンジンにも取り組んでいます。このGCのインターフェイスは、複数のGCエンジンを使用したり特定のタスクに合わせてGCをチューニングしたりできるように分離が進められています。
このGCは次に示す複数の領域を走査して管理対象オブジェクトへのポインタを探します。
- ヒープ(他の管理対象オブジェクトが割り当てられている場所)
現在、ヒープはほぼ高精度なモードで処理されています。このGCは必ずといっていいほど、ヒープへの参照だけを含むメモリワードだけを考慮するため、ポインタの誤認やその結果としてのメモリリテンションが生じることはほとんどありません。この新しいGCでは、状況を改善するには十分に高精度なモードが必要です。具体的には、参照のビットマップが疎であるようなラージオブジェクトを処理したり、複数のAppDomainを安全に処理したりする必要があります。 - スレッドスタックとスレッドレジスタ
これらは常に保守的に走査されます。この点はMonoの新GCでも(少なくとも、MonoチームがGCの世代移行によって生じたバグを追跡する必要がある初期バージョンでは)変わりません。将来的には、スタックの非管理対象部分だけを保守的に走査するようになるでしょう。 - 静的データ領域
すでにこの部分はBoehm GCと新GCのどちらでも高精度モードで動作するようにMonoチームによって最適化されています。 - ランタイムによって割り当てられるデータ構造
すでにこの部分はおおよそ高精度なモードで動作するようにMonoチームによって最適化されています(つまり、データ構造によって高精度で処理されるものとそうでないものがある)。ただし、特に新しいGCについてはピンドオブジェクトの存在が大きな問題を引き起こす可能性があるため、Monoチームはこの部分に対してさらに取り組む必要があります。
コンパクト化GC(Compacting GC)
Monoチームは新世代の高精度なコンパクト化GCの開発を進めています。現在、このGCはMonoのSVNリリースから入手できます。この新しいコンパクト化GCは、完全に保守的なGCのいくつかの制限(具体的には、ヒープの断片化によって生じるメモリの消費など)を回避するために実装されました。
この新しいGCは現在SVNから入手できますが、サポート対象の構成にはなっておらず、Mono 2.4のリリースでもサポート対象の構成にはなっていません。アプリケーションのテストに関心がある開発者や、新しいGCを試したい開発者は利用するとよいでしょう。
実装の詳細は、Monoの「Compacting GC」(コンパクト化GC)のページに記載されています。
最適化
JITエンジンには、次のような最適化が実装されています。
- オペコードのコスト見積り(MonoのアーキテクチャのおかげでMonoチームはさまざまなコードパスをターゲットCPUに応じて動的に生成できる)
- インライン展開
- 定数のたたみ込み、コピー伝播、デッドコードの削除(コンパイラは通常、定数のたたみ込みを行うが、これにインライン展開を組み合わせることで良好な結果が得られる)
- 線型走査レジスタ割り当て
- SSAベースのフレームワーク(さまざまな最適化がこのフレームワーク上に実装されている)
MonoチームはJITエンジンの改良を続けていますが、多くの最適化はプログラム実行時に行っても効果が得られません。アプリケーションの実行パターンのプロファイリングと調査を行えば、かなり良い結果が得られるでしょう。ソフトウェアのチューニング方法に関するさまざまなアイデアについては、Monoの「Performance Tips(パフォーマンスに関するヒント)」の記事を参照してください。
