2007/7/18 水曜日

PowerShell の起動を高速化する

Filed under: Powershell — flamework @ 22:41:09

PowerShell の起動が遅い理由

PowerShell に限らず .NET Framework で構成されたアプリケーションは、OS起動後、初めての起動で大変時間がかかります。これには理由があります。

まず、.NET Framework 以前のアプリケーションは、「マシン語」と呼ばれる、 CPU が直接理解できる言語で書かれています。たとえ C 言語や VisualBasic などの「高級言語」で開発されたとしても、最終的にはマシン語に直さないと CPU はこれを実行できません。したがって、コンパイラやインタプリタが、翻訳の労を担います。

.NET Framework の場合、アセンブリは IL と呼ばれる中間言語で書かれています。中間言語ですから、これは直接実行できません。そのため、初めての起動では、JIT(Just In Time)コンパイラがこれをマシン語に翻訳します。

これが、.NET Framework アプリケーションの起動に時間がかかる理由です。

Ngen.exe

.NET Framework には、ネイティブ イメージ ジェネレータ (Ngen.exe) というツールが付属しています。

参照: MSDN「ネイティブ イメージ ジェネレータ (Ngen.exe)」

これは、IL で書かれたアセンブリをマシン語にコンパイルし、「ネイティブ イメージ キャッシュ」と呼ばれる場所にインストールするツールです。ネイティブイメージキャッシュにインストールされたアセンブリは、直接実行できますので、起動が高速化されるというわけです。

ダウンロード

以下のスクリプトを実行すると、現在ロードされているアセンブリを、すべてネイティブイメージキャッシュにインストールします。


 

  • No Related Post

2007/7/15 日曜日

メモリリークのない C# の実行

Filed under: Powershell — flamework @ 22:36:32

アプリケーションドメイン

前回、「PowerShell で C# の実行」では、メモリ内に動的アセンブリをコンパイルする方法をご紹介しました。しかし、この方法では、PowerShell を終了するまで解放できない動的アセンブリがメモリ内に次々に増えていくことを問題点として挙げました。今回ご紹介するのは、アプリケーションドメインを使ってアセンブリを解放する方法です。アプリケーションドメインについての詳細は、以下をご覧ください。


 

アプリケーションドメインを使う

.NET のプロセスは、1 つ以上のアプリケーションドメインで成り立っていて、アセンブリは、いずれかのアプリケーションドメイン内にロードされます。アセンブリだけを単独で解放する手段はありませんが、アプリケーションドメインを解放することで、そこに読み込まれたアセンブリが解放されます。そこで、新しくアプリケーションドメインを作成し、そこにコンパイル済みのアセンブリを読み込んで実行し、終了後にアプリケーションドメインを解放する、という方法を採ることにします。


 

ダウンロード

以下より、メモリリーク無しで C# を実行するスクリプトをダウンロードできます。


 

用例

前回の用例がそのまま使えますので、ご覧ください。ただし、前回の Invoke-Cs.ps1 では可能であった、「新しい型を作成して使用すること」が、今回の Invoke-CsRemote.ps1 ではできなくなっています。

用例: 新しい型の作成

PS > Get-Content hello.cs
class Program {
    static object Main()
    {
        return new Program();
    }
    public string Hello()
    {
        return "Hello World!";
    }
}
PS > $a = Invoke-Cs hello.cs
PS > $a.Hello()
Hello World!
    ※ Invoke-Cs では成功
PS > $a = Invoke-CsRemote hello.cs
"5" 個の引数を指定して "InvokeMember" を呼び出し中に例外が発生しました: "呼び出しのターゲットが例外をスローしました。" 発生場所 Invoke-CsRemote.ps1:70 文字:57 +         $result = [Runtime.Remoting.ObjectHandle].InvokeMember( <<<< 'Unwrap', 'InvokeMethod', $null, $objectHandle, $null)
    ※ Invoke-CsRemote では失敗

これはなぜかと言うと、新しい型を作成したアセンブリが別のアプリケーションドメインにあるために、型情報を読み込むことができないからです。

Invoke-Cs と Invoke-CsRemote の使い分け

Invoke-Cs は、 PowerShell を終了するまでアセンブリを保持し続けます。これはメモリリークの原因となりますので、できる限り Invoke-CsRemote を使うのが良いでしょう。ただし、新しい型を作る必要がある場合には Invoke-Cs のような方法を使わざるをえません。その場合でも、作ったアセンブリをその度に使い捨てにするのではなく、一度作成した型を何度も再利用することで、メモリリークを防ぐことができます。また、頻繁に同じ C# ソースを実行するようであれば、恒常的なアセンブリにコンパイルすることを検討すべきかもしれません。

« 前ページへ次ページへ »

Copyright © flamework.net 2008.