起動、それから

実行可能 .NET アセンブリ*1 *2が起動されると、ネイティブアプリケーション同様にプロセスが生成されてイメージファイルがプロセス空間にマッピングされてエントリポイントから実行が始まる。ネイティブアプリケーションとしてのエントリポイントは、標準的な設定の CLR ホストを作成し最初のアプリケーションドメインを作成した後、*3 *4エントリメソッドを実行する。C# の場合はモジュールメソッドを作成できないため、エントリメソッドは特定のクラスの static なメソッドとなる。*5
エントリメソッドが呼び出される前に、最初のアセンブリがロードされ、そのマニフェスト情報から外部参照の解決が試みられる。この時点で参照アセンブリ*6はすべてメモリ空間上にマップされる。アセンブリが様々な経路・探査・取得方法あるいはシャドウコピーを経由してなんとか読み込まれると、メソッドの実行に必要な型やメソッドそのものが JIT コンパイルされるため、コンパイル済みのものがないか、内部バージョン*7の比較なんが行われたあとに JIT コンパイルが行われ、実際にメソッドが実行される。


そこそこ大規模な Windows Forms アプリケーションであれば、System.Windows.Forms.dll をはじめとした .NET のベースライブラリ群と自身の構成する DLL 群をあわせて 20〜30MB のサイズにはなるだろう。この時点で WorkingSet が 30〜40MB 程度には膨れ上がるが、その 90% 以上はファイルマップエントリであり、読み込みディスクキャッシュを除外すると多く見ても 1MB 程度のメモリを消費している状態になる。
しかし、Win32 プロセス情報としては、仮想メモリサイズは 100MB こえ、WorkingSet は 50M に迫り、初回起動時には(ハードウェア性能にもよるが)この段階に達するまで十数秒から二十数秒かかってしまう。
コレをエンドユーザに理解してもらうのは難しいですね。

なんていうか、無理やりエントリ作ると

余計なこと書いてある部分と、すごく端折ってある部分が交錯してて、自分らしい文章になった(笑

*1:厳密には、アセンブリはモジュールを構成する抽象単位であって、Windows 上などでファイルとして見えて実行したりできるものはモジュールである

*2:世間的にはシングルモジュールアセンブリが主流であり、シングルモジュールアセンブリアセンブリと呼ぶことになんら問題はないだろう

*3:まだ存在しないならば、システムアプリケーションドメインなどが先に作成される

*4:はじめて CLR を起したならば、合計3つのアプリケーションドメインが生成されることになる

*5:VBC# では、このメソッドの名前は Main 固定になっている

*6:アセンブリそのもののこと、つまりメインモジュールのことであり、概ね .DLL ファイルそのもの

*7:アセンブリに設定できるバージョン情報ではなく、自動的に設定されるほうのバージョン情報