none
.NetFrameworkアプリケーションを初回読み込みから速くするには?

    質問

  • C#を使用し、.NetFrameworkを使用したWindowsアプリケーションを開発し、販売しております。

    初歩的な質問と思いますが、.NetFrameworkを使用したアプリケーションにおいて、
    初回の読み込みが遅い問題の対策というものはありますでしょうか?

    .NetFrameworkの仕様上の制限
    (2度目以降の読込はNetFrameworkのキャッシュ機能によってはやくなるが、初回は遅い)かと思うのですが、
    たびたび、お客様から「遅い!」とよく問い合わせがきてしまいますので、
    初回から読み込みを速くする方法がないか調べております。。。

    もし、初回の読み込みからはやくする方法があるなら教えていただいてもよろしいでしょうか。
    (例えば、インストーラにキャッシュデータも含めておき配布するなど)

    お手数をおかけいたしますが、よろしくお願いいたします。
    2010年1月13日 7:18

すべての返信

  • NGen してますか?
    2010年1月13日 9:39
  • 私がユーザーから起動を早く出来ないかと言われた時にテストした限りでは、スタンバイや休止ではない完全な終了状態からWindowsを起動してログオンし、最初に起動する時の起動時間についてはngenはほとんど効果ありませんでした。
    テスト結果はうろ覚えなので正確な時間はわからないのですが、2回目起動が5秒くらいで済むのが、初回は1分以上が頻繁に発生してました。(ILMergeで全部まとめてngenしてある1MB弱のexeと50kB位のネイティブdllです。)
    Windowsが読み込みを遅延させてるのかもと考えてしばらく待ってからの起動でも同じような結果になりました。

    このときの苦肉の策は、インストーラーでレジストリのrunスタートアップにダミー起動を登録し、ユーザーの体感時間を減らすようにしました。
    ダミー起動はMainの呼び出しで引数を見て判断して、何も処理せず終了させてます。


    #インストーラーでWindowsの起動が遅くなりますよと警告した上でのオプションで登録するかしないかの選択はさせてますが。

    もっと早くできる方法があるなら、ぜひとも私も知りたいです…

    追記
    ついでにインストーラーからもダミー起動を実行させてインストール直後の起動も早くなっているように見せてました(^^
    • 編集済み gekkaMVP 2010年1月13日 12:22 ちょっと追記
    2010年1月13日 12:14
  • .NetFrameworkの仕様上の制限
    (2度目以降の読込はNetFrameworkのキャッシュ機能によってはやくなるが、初回は遅い)かと思うのですが、
    たびたび、お客様から「遅い!」とよく問い合わせがきてしまいますので、
    初回から読み込みを速くする方法がないか調べております。。。

    問い合わせが頻繁にくるとは尋常じゃないですね。でも実際どれくらい遅いのでしょうか?
    またアプリの用途や、客先のマシンのスペックによって、許容できる起動時間が変わってくると思うのですが。。。
    2010年1月13日 14:24
    モデレータ
  • ところで、初回が遅い、って誰が判断するんでしょうね。
    2回目以降で高速化したことに気付いた人は、普通それで満足するはずですし。
    後から思い出したように「あの時(初回のこと)はもっと高速に動作したはずだ!」って問い合わせが多いんですかねぇ…。
    # ものすごくレアな問い合わせだと思うんですけど…。

    って考えると、そういう次元ではなく作られたプログラムが、利用者の自身のPCスペックと照らし合わせて「遅いはずだ!」っていう問い合わせような気がするんですが。
    2010年1月13日 22:57
  • おそらく、本当の初回起動で .NET Framework が作成するシステム AppDomain (名称うろおぼえ) の初期化時間の話ではないかと思います。現状の対策で正解でしょう。static class Program { static void Main() {} } の1行だけのプログラムでも十分です。

    2010年1月14日 0:06
  • > .NetFrameworkの仕様上の制限
    > (2度目以降の読込はNetFrameworkのキャッシュ機能によってはやくなるが、初回は遅い)かと思うのですが、
    > たびたび、お客様から「遅い!」とよく問い合わせがきてしまいますので、
    > 初回から読み込みを速くする方法がないか調べております。。。

    ちなみに、いま開発しているシステムで試してみました。

    テストマシンのスペック
    -------------------------------
    マシン: Dell Vostro 220
    CPU: Intel Dual-Core E2200 2.20GHz
    メモリ: 2GB
    OS:Windows XP SP3
    -------------------------------

    OSを起動直後にアプリケーションを起動、
    ログイン画面→メニュー画面→もっとも重い画面を表示してみる。

    一番ヘビーな画面では・・・

    1.地図用 ActiveX コントロールを搭載。ちなみに地図データは WEB サーバーから取得
    2.コントロール数は、ラベルも含めて300個近く。
    3.GrapeCity の InputMan 使用
    3.諸般の事情により、TableLayoutPanel ネストしまくり(苦笑)
    4.DB は、リモートの MySQL サーバーに接続

    初回ではアプリケーション起動から、この画面表示まで約15~20秒。二回目以降で約3秒
    すでに導入している会社も幾つかありますが、ユーザビリティにうるさい顧客でも、
    表示状態変更時に画面がちらつく等の指摘はあっても、起動時間で問題になったことは今までないんですよね。

    2010年1月14日 1:58
    モデレータ
  • >おそらく、本当の初回起動で .NET Framework が作成するシステム AppDomain (名称うろおぼえ) の初期化時間の話ではないかと思います。

    「システム AppDomain」というものはありません。

    AppDomain は、.NET アプリケーションをホストするプロセス内に作成される論理的な領域で、システムグローバルな AppDomain は存在しません。
    2010年1月14日 7:14
    モデレータ
  • >おそらく、本当の初回起動で .NET Framework が作成するシステム AppDomain (名称うろおぼえ) の初期化時間の話ではないかと思います。

    「システム AppDomain」というものはありません。

    AppDomain は、.NET アプリケーションをホストするプロセス内に作成される論理的な領域で、システムグローバルな AppDomain は存在しません。

    そうですよね。

    だとすると、何が2度目以降の起動時間が早くなる理由なのでしょうか・・・?
    システムグローバルなものでぱっと思いつくのは、システムキャッシュぐらい?これだけではこんなに早くならないですよね。

    何が起動時間がこんなにも違う理由なのか、私も知りたいです。
    2010年1月14日 8:39
  • >だとすると、何が2度目以降の起動時間が早くなる理由なのでしょうか・・・?

    初回起動時はアプリケーションの起動に必要なアセンブリが JIT 実行され、2回目以降は初回起動時の JIT の結果が再使用されるから、というのが大きいと思います。

    なので、アプリケーションに大きく手を加えないで済ましたい場合

    >このときの苦肉の策は、インストーラーでレジストリのrunスタートアップにダミー起動を登録し、ユーザーの体感時間を減らすようにしました。
    >ダミー起動はMainの呼び出しで引数を見て判断して、何も処理せず終了させてます。

    という対策は妥当なものです。

    細かく詰めていくなら

    ・アプリケーションの初期化シーケンスを見直す(=不要な処理は行わない)
    ・アプリケーションの構成要素(コードや定義、リソースなど)のアセンブリへの配分を見直す(=起動に不要な要素は別アセンブリに移動する)

    などの対策が考えられるでしょうか。

    2010年1月14日 8:47
    モデレータ
  • 皆様、ご回答いただき誠にありがとうございます。
    大変参考になります。

    現在、gekka様に教えていただきました方法で試しております。
    以下の方法で、初回起動から、各画面が速く開けるようになることを確認いたしました。

    1.アプリケーショの各画面にキャッシュ作成用の関数(何もせずに終了する関数)を定義
    2.アプリケーションの最初のログイン画面にて、別スレッドで上記関数をコールし、キャッシュを作成

    ただ、上記の方法で速くしても、アプリケーションプロセスを終了したタイミングで
    キャッシュが消えてしまうため、アプリケーションの起動時に毎回キャッシュ作成の処理が必要になるようでした。

    現在はテスト用にログイン画面でキャッシュの作成処理を行っていますが、
    できれば、OSの起動時にrunスクリプト等で1度だけキャッシュ作成処理を行い、
    OSを終了するまでは、常にそのキャッシュを使用したいと思います。

    上記の動作を確認した限りですと、キャッシュ情報はメモリー内の、
    アプリケーションプロセス内に記憶されている(?)と認識しているのですが、、
    もし、Windows起動直後にキャッシュを作成する方法を行いたい場合は、
    アプリケーションプロセスをOS起動から裏で常駐させておく必要があるということでしょうか?

    たびたび申し訳ございませんが、
    もしアドバイスがございましたらよろしくお願いいたします。

    2010年1月14日 9:38
  • あれ?
    「初回の読み込みが遅い」とは、「各画面(Form)の初回の読み込みが遅い」のことですか?

    # ちなみに、ngen の効果ってあるかどうか見られました?


    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年1月14日 14:50
    モデレータ
  • >だとすると、何が2度目以降の起動時間が早くなる理由なのでしょうか・・・?

    初回起動時はアプリケーションの起動に必要なアセンブリが JIT 実行され、2回目以降は初回起動時の JIT の結果が再使用されるから、というのが大きいと思います。

    .NET Framework 開発者ガイド
    MSIL からネイティブ コードへのコンパイル
    http://msdn.microsoft.com/ja-jp/library/ht8ecch6.aspx


    Just-In-Time コンパイラによるコンパイル に、

    JIT コンパイルは、実行時に呼び出されることがないコードがあることを考慮しています。つまり、ポータブル実行可能 (PE) ファイル内にあるすべての MSIL をネイディブ コードに変換するために時間とメモリを費やすのではなく、実行時に必要とされる MSIL を変換し、結果として生成されるネイティブ コードをメモリに保存します。こうすることで、そのプロセスのコンテキスト内の後続の呼び出しでこれを利用できます。型が読み込まれて初期化されるとき、ローダーはスタブを作成し、その型の各メソッドにそれを結び付けます。

    と説明されています。

    つまり、JIT の結果がプロセスを超えて再使用されることがない、と解釈しているのですが、実際にはプロセスを超えて再使用されているかのように起動時間が早くなってしまうので、何が理由?といろいろ調べているのですが、結論めいた結論に至れないでいます。
    2010年1月15日 0:04
  • > 「システム AppDomain」というものはありません。

    App とつけると アプリケーション を示すようで誤解を受けやすいんですかね。
    (.NET 1.1 時代の)古い記事なのですが、

    http://msdn.microsoft.com/en-us/magazine/cc163791.aspx

    上記の記事では、System Domain と Shared Domain という名前で呼んでいますね。

    初めて、.NET ランタイムが初期化されるときに、こOS 全体にグローバルな AppDomain が2つ作成されるとされています。この初期化時間がかなりかかるので、前述の投稿のようにスタートアップに Main() 関数だけの空プログラムを配置しておくことで事前に初期化をしてしまえます。

    .NET 2.0/3.0/3.5 であっても、上記は十分に有効な回避手段で、初回起動の時間としては、ngen とかアホらしくなるほどの差異が発生します。(効果のオーダーが1~2桁違います)
    • 編集済み K. Takaoka 2010年1月15日 4:10 助詞を直しただけ
    2010年1月15日 4:06
  • 初めて、.NET ランタイムが初期化されるときに、こOS 全体にグローバルな AppDomain が2つ作成されるとされています。この初期化時間がかなりかかるので、前述の投稿のようにスタートアップに Main() 関数だけの空プログラムを配置しておくことで事前に初期化をしてしまえます。

    .NET 2.0/3.0/3.5 であっても、上記は十分に有効な回避手段で、初回起動の時間としては、ngen とかアホらしくなるほどの差異が発生します。(効果のオーダーが1~2桁違います)

    面白そうなので試してみました。
    上記レスにある環境で .NET 3.5 のアプリですが、体感速度的に変わってないような気が・・・
    2010年1月15日 7:52
    モデレータ
  • 面白そうなので試してみました。
    上記レスにある環境で .NET 3.5 のアプリですが、体感速度的に変わってないような気が・・・
    「.NET 3.5 のアプリ」ではなく、OS や .NET Framework のバージョンを記すべきです。
    どのバージョンをターゲットにしたアプリかは、.NET Framework 2.0~3.5 の間においてはあまり関係ありません。

    例えば、.NET Framework 2.0 向けに作ったとしても、実行環境が .NET Framework 3.5 SP1 であれば、その変更点による効果があります。(共有フォルダから実行できるようになるなど)

    また、どの程度の効果があるかは存じませんが、.NET Framework 3.5 SP1 の変更点に起動時間の改善があります。
    少なくとも、インストールされている .NET Framework のバージョンを合わせないと、議論が成り立ちません。
    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年1月15日 16:02
    モデレータ
  • さて、このスレッドにおいて、下記の 2 つの話が混ざっているように見受けられます。
    スレッドを立てた サイタマン さんはどちらが目的でしょうか?

    (1)最初の .NET Framework アプリケーションの実行が遅い。どれでも良いから、1度でも .NET Framework アプリケーションを実行すれば速くなる。
    (2)最初に画面が表示されるときが遅い。2度目以降の表示は速いが、アプリケーションを再起動するとやっぱり1度目が遅い。


    もし、(2)であるならば、(1)に対する議論は別のスレッドに分けるべきだと思います。
    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年1月15日 16:04
    モデレータ
  • 「.NET 3.5 のアプリ」ではなく、OS や .NET Framework のバージョンを記すべきです。
    どのバージョンをターゲットにしたアプリかは、.NET Framework 2.0~3.5 の間においてはあまり関係ありません。
    ・・・中略・・・
    少なくとも、インストールされている .NET Framework のバージョンを合わせないと、議論が成り立ちません。

    表現きつ!!まぁでも確かに仰るとおりです。(^ω^;

    上にも書きましたが補足です。

    テストマシンのスペック
    -------------------------------
    マシン: Dell Vostro 220
    CPU: Intel Dual-Core E2200 2.20GHz
    メモリ: 2GB
    OS:Windows XP SP3
    .NET Framework 3.5 SP1 インストール済み
    Visual Studio 2010 beta2 インストール済み(これはあまり関係ない?)
    -------------------------------

    > スタートアップに Main() 関数だけの空プログラムを配置しておくことで事前に初期化

    した場合としてない場合、両方試してみました。
    なお起動直後はサービスやらバックグラウンドで動くアプリやら何やら起ち上がるので
    System Idle Process が CPU使用率 90%以上で安定するまで待機してから実行してます。

    > OSを起動直後にアプリケーションを起動、
    > ログイン画面→メニュー画面→もっとも重い画面を表示してみる。

    結果: どちらも約20~30秒。体感速度変わらず。(-ω-)
    本当は Stopwatch 組み込めれば正確な数値が出るのでしょうが、開発中の製品で試しているので、さすがにそこまでしてません。



    2010年1月15日 16:49
    モデレータ
  • 参考まで。
    http://msdn.microsoft.com/ja-jp/magazine/cc337892.aspx

    http://msdn.microsoft.com/ja-jp/magazine/dd569747.aspx

    もっとも、

    >> OSを起動直後にアプリケーションを起動、
    >> ログイン画面→メニュー画面→もっとも重い画面を表示してみる。

    >結果: どちらも約20~30秒。体感速度変わらず。(-ω-)
    こういう感じ(ちょっと具体的にどこで遅いのかは分かりませんが)であれば、

    >(2)最初に画面が表示されるときが遅い。2度目以降の表示は速いが、アプリケーションを再起動するとやっぱり1度目が遅い。
    こっちの観点ですね。
    普通にどこで遅いのか調べて何が遅いのか調べてっていう方向での調査と検討になるでしょう。

    2010年1月15日 18:32
  • > インストーラーでレジストリのrunスタートアップにダミー起動を登録し、ユーザーの体感時間を減らすようにしました。
    > ダミー起動はMainの呼び出しで引数を見て判断して、何も処理せず終了させてます。

    という話があったので (1) に限定した話だと思っていたのですが、冒頭のサイタマンさんの投稿ではなかったんですね。
    問題になっているサイタマンさんの状況が (1) なのか (2) なのかはわかりませんが、一般的に「アプリケーションの1度目の起動時間が遅い」という質問に対する回答としては、(1) と (2) は、共に必要な議論であることは間違いありません。(どちらも解消されなければ、根本的な問題の解決にならない)

    そういった意味で、スレッドは分けるべきではないのかも? という気もします。「それには2つの要因があって、それぞれ別の観点でアプローチする必要があるんだよ」という回答はよいと思うのですが、質問者や検索者にとって必要なのは両方であって片一方ではないことがほとんどであろうと思います。

        class Program
        {
            static void Main(string[] args)
            {
    #if PRINT
                System.Console.WriteLine(
                    System.Diagnostics.Process.GetCurrentProcess()
                        .StartTime.ToString("yyyy-MM-dd hh:mm:ss.ff")
                );
    
                System.Console.WriteLine(
                    System.DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss.ff"));
    #endif
            }
        }
    PRINT を定義したプログラム test.exe と、PRINT を定義していない autorun.exe の2つにコンパイルしておいて、手元の .NET Framework 3.5 SP1 環境および、同一マシンにて構成ファイルを使用して .NET Framework 2.0 を明示した場合、

    # 3.5SP1 without autorun.exe
    > test.exe
    2010-01-16 09:59:53.53
    2010-01-16 09:59:55.58
    

    # 3.5SP1 with autorun.exe > test.exe 2010-01-16 10:12:59.29
    2010-01-16 10:13:00.07

    # 2.0 without autorun.exe 2010-01-16 10:16:56.55 2010-01-16 10:16:59.28

    # 2.0 with autorun.exe 2010-01-16 10:20:03.64 2010-01-16 10:20:04.47

    こんなかんじでした。
    計測精度は別おいといて、2050ms, 780ms, 2730ms, 830ms ですね。3.5 SP1 は、それ自身で起動速度がかなり改善されているように見えます。
    • 編集済み K. Takaoka 2010年1月16日 1:23 誤変換:要員→要因
    2010年1月16日 1:22
  • そういった意味で、スレッドは分けるべきではないのかも? という気もします。「それには2つの要因があって、それぞれ別の観点でアプローチする必要があるんだよ」という回答はよいと思うのですが、質問者や検索者にとって必要なのは両方であって片一方ではないことがほとんどであろうと思います。
    確かにそうかもしれません。(どちらが理想かは正直まだ分からない印象です)

    どちらについて述べているか分かる投稿になっていることと、サイタマンさんのところで生じている問題が解消できる、あるいはそれに近い結果が得られるのであれば、良いと思っています。
    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年1月16日 3:25
    モデレータ
  • > 初めて、.NET ランタイムが初期化されるときに、こOS 全体にグローバルな AppDomain が2つ作成されるとされています。

    http://blogs.wankuma.com/yaju/archive/2007/05/07/75689.aspx


    OS 全体で1個なんですか?アプリケーションごとに、と理解されている方もいらっしゃるようですが。
    日本語→ http://www.microsoft.com/japan/msdn/msdnmag/issues/05/05/JITCompiler/default.aspx



    1).NET Framework を使用するアプリケーション全体で、初回の起動が遅いのか。
    2)1つのアプリケーションで、起動から終了までのライフサイクルのうち、フォームの初回表示のみが遅いのか。

    これは、違う問題だと思います。1の方は、ログオン単位または OS の起動単位で何らかの対策が必要でしょう。
    しかし、2の方は1つのアプリケーションの中で完結するのではないでしょうか。
    Azuleanさんのおっしゃっているのはそういうことだと思ったのですが、違いました?
    Jitta@わんくま同盟
    2010年1月16日 12:46
  • これは、違う問題だと思います。1の方は、ログオン単位または OS の起動単位で何らかの対策が必要でしょう。
    しかし、2の方は1つのアプリケーションの中で完結するのではないでしょうか。
    Azuleanさんのおっしゃっているのはそういうことだと思ったのですが、違いました?
    そういうことですが、両方の問題を抱えている可能性があると言われると否定できません。
    ですので、サイタマンさんの追加情報を待とうと思っています。

    # 今の時点で両方について議論しても、質問者を置いてきぼりにしかねませんし。
    質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。
    2010年1月16日 13:28
    モデレータ
  • > アプリケーションごとに、と理解されている方もいらっしゃるようですが

    (すいません、時間の都合で読み返してないのですが、)たしかに、プロセス単位なかんじでした。申し訳ありません。

    というわけで、以下のように訂正させて頂きます。

    ---
    .NET ランタイムが初期化されるときに、内部的に全プロセスで共通な AppDomain が2つ作成されるとされています。この初期化時間がかなりかかるのですが、前述の投稿のようにスタートアップに Main() 関数だけの空プログラムを配置しておくことで、この時間を大幅に短縮することができるようになります。
    ---

    私が、こういった場に投稿する目的は、間違いを指摘してもらうためなので、こういう話があると大変うれしく思います^^
    起動時に (Main から呼ばれる static initializer までを含めて) 暗黙的に参照されるアセンブリの量で、この短縮される部分の時間が大幅に違いがでることから、OS 全体で実行イメージではない何かを調べているのは間違いないんですけどね。

    このタイミングで実行されることって多いようで少ないですよね。mscorlib や System.Windows.Forms 等の、(ngen によって) pre-JIT されたイメージの整合性チェックとかが山のように実行されると思いますが、これはアセンブリローダーが毎回やるでしょうし…。

    > これは、違う問題だと思います。

    前にも書いたことと同じような言い方になりますが、ユーザから見える挙動は、「(1) + (2) の時間が遅い」でしかないです。サイタマンさんにしても Gekka さんにしても、解決したい問題がこのことであることは明白ですよね。

    この質問が運用的な問題の話であって、その技術的に解決しなければならない問題が (1), (2) の2つあると捉えて同じレベルで語られるべきだろうと思います。Azulean さんの書かれているように、解決策や技術的な問題点として、この2つをはっきりと区別して話す必要がある、というのは同意…というより、そんなことは当たり前のことだと思っています。それとは別に、技術的な問題点と運用的な問題点を同一視することはできません。

    (すでに挙げられている記事にもあるかと思いますが、) (2) の問題の手軽な解決策として ngen が、あまり……いや、ほとんど……役に立たないことは、起動時間の短縮に苦労したことがある人なら、みんな体感して知ってるんじゃないかと思います。
    2010年1月16日 14:28
  • > 私が、こういった場に投稿する目的は、間違いを指摘してもらうためなので、こういう話があると大変うれしく思います^^

    あ、いや、「間違っている」とは、言っていません。むしろ、私も最初に見たときには、「Singleton」という言葉より、全体で1つの System Domain と Shread Domain が作られると思いました。しかし、検索しているうちにやじゅさんの記事が見つかって、そこにはアプリケーション単位と書いてある。やじゅさんところには「アプリケーション」という枠の中に書いてあるので「プロセスごとに1つ」の様に見えますが、元記事には「マネージプロセスの3つのドメイン」と書いてある。(まだ内容をじっくり読んだわけではないので)さて、いったいどっちなんだろう?・・・と思った次第です。
    しかし、


    > ユーザから見える挙動は、「(1) + (2) の時間が遅い」でしかないです。

    そうでしょうか。(1)であれば、再起動するまでは、どの画面も同じように速いのです。(2)は、一度終了してしまうと、1度は遅くなります。
    もっとも、エンドユーザーがどのように理解される/開発者へ伝えるかは、どちらも同じとなるでしょうが、開発者の方がそれなりに調べた結果、ここへ書き込みをされていると、私は理解しているのですが。。。先に書いたように、(1)と(2)で、対策方法が違うと考えられます。どちらかがはっきりしないと、後でこのスレッドを見る人も含めて、混乱させるのではないかと思います。


    Jitta@わんくま同盟
    2010年1月17日 13:57
  • このたびはご回答いただきありがとうございます。
    また、このたびは返信が遅くなっしまったことを深くお詫び申し上げます。

    また、混乱させてしまい申し訳ございません。私はてっきり、
    「NetFrameworkアプリケーションが遅い問題」の中に、「Formの読み込みが遅い問題」も含まれている(つまり、どちらの問題も原因は同じ)
    と認識しておりましたが、それぞれ、別の原因(と、別の対策方法)があるということですね。

    まずは、どちらの問題かをはっきりしなければいけないと思うのですが、私自身が、いまいちわかっておりません。。。
    (1度めの処理が遅く、2度目の処理ははやくなることまでは確認しているのですが、原因の細かな切り分け方法がわかりませんでした。)

    そこで、1点確認させていただきたいのですが、前回、
    >1.アプリケーションの各画面にキャッシュ作成用の関数(何もせずに終了する関数)を定義
    >2.アプリケーションの最初のログイン画面にて、別スレッドで上記関数をコールし、キャッシュを作成
    の対策にて、1回目から読み込みがはやくなった(が、アプリケーションプロセスを再起動すると遅くなってしまった)と申し上げたと思うのですが、

    ------------------------------------------------------------------------------
    ①この対策は、「NetFrameworkアプリケーションが遅い問題(JITもしくはApp
     Domain上の問題)」の対策となり、もし、アプリケーションプロセスを再起動
     した後の1度目の処理もはやくしたい場合は、別途、「フォームの読み込みが
     遅い問題」の対策を実施する必要がある
    ------------------------------------------------------------------------------

    ということになりますでしょうか?それとも、
    ------------------------------------------------------------------------------
    ②これまでの情報だけでは、どちらの問題かわからないため、
     まずは、何らかの方法でどちらの問題かを切り分ける必要がある
    ------------------------------------------------------------------------------

    ということになりますでしょうか?
    (もし、①ということでしたら、できればアプリケーションプロセスを再起動した後の1度目の処理も早くしたいと思いますので、
    別途フォームの読み込みが遅い問題の対策があるようでしたら教えていただきたいと思っております。
    また、もし②の状態でしたら、切り分け方法をご教授いただければと思います。勉強不足で申し訳ございません。)

    #なお、環境につきましては、VisualStudio2008(.NetFrameworkは3.5 SP1)となります。
    #現在は、ngen につきまして調べております。結果につきましては、わかり次第ご報告いたしますので、
     もうしばらくお時間をいただいてもよろしいでしょうか。

    質問ばかりしてしまい、
    大変申し訳ございませんが、何卒よろしくお願いいたします。

    2010年1月18日 1:42
  • 自己レスいたします。

    「.NET Framework アプリケーションの問題」は、
    >最初の .NET Framework アプリケーションの実行が遅い。どれでも良いから、1度でも .NET Framework アプリケーションを実行すれば速くなる。
    と書いていましたね。確認不足で申し訳ございません。

    試しに、他の.NetFrameworkアプリケーションを実行した後、
    問題のアプリケーションを起動した場合、1度目の速度も若干はやくなりましたが、ほとんどかわりませんでしたので、
    私の環境で発生している問題は、「1度目のフォームの読込が遅い問題」になります。

    他のサイトで同様の質問をしているサイトを見つけましたので、URLをお送ります。(結論としては「しょうがない」ということになっていましたが。。。)
    http://questionbox.jp.msn.com/qa1823978.html
    こちらと同じ現象になります。

    また、目的といたしましては、アプリケーションプロセスを再起動した後も含め、
    1度目から処理を早くしたいと思っています。

    OSの起動時にrunスクリプト等で1度だけキャッシュ作成処理を行い、
    OSを終了するまで、常にそのキャッシュを使用する方法で、
    フォームの読込をもしはやくできるようでしたら、
    その方法を教えていただいてもよろしいでしょうか。

    たびたび申し訳ございませんが、よろしくお願いいたします。

    2010年1月18日 2:32
  • > 参考まで。
    > http://msdn.microsoft.com/ja-jp/magazine/cc337892.aspx
    > http://msdn.microsoft.com/ja-jp/magazine/dd569747.aspx

    貴重な情報ありがとうございます。
    なるほど・・・.NET Framework 3.5 SP1 では大幅な改善が施されているのですね。
    大変参考になります。


    さて・・・スタートアップのダミー起動のアプリを

    > static class Program { static void Main() {} }

    だけでなく、ダミーの Forms アプリケーションを作成し、
    初回起動を高速化したいアプリケーションで使われている特にヘビーと思われるアセンブリを組み込み
    Main は Formを表示せず、インスタンスのみを生成廃棄するだけにするよう処理を組んでみました。

    namespace Starter
    {
        static class Program
        {
            /// <summary>
            /// アプリケーションのメイン エントリ ポイントです。
            /// </summary>
            [STAThread]
            static void Main()
            {
                Form1 form = new Form1();
                try {
                    form.BackColor = System.Drawing.Color.Red;
             }
             finally {
                    form.Dispose();
             }
            }
        }
    }

    Form1 には、開発システムで使っている地図コントロールやら
    InputMan・MultiRow 等のGrapeCityコントロール、その他諸々
    いろんなアセンブリのコントロールを貼り付けてみました。

    読み込まれたアセンブリの一覧・・・

    Microsoft.VisualBasic.PowerPacks
    ActiveReports3
    ActiveReports.Viewer3
    GrapeCity.Framework.MultiRow
    GrapeCity.Win.MultiRow
    GrapeCity.Win.Editors
    MySql.Data
    その他、地図OCX のラッパーアセンブリ・・・他

    このアプリをスタートアップに設定したら二回目起動に及ばないものの、体感速度が大幅に向上しました。

    > static class Program { static void Main() {} }

    で約20~30秒だったのが、10秒前後まで速くなりました。
    どうやらシステムで使うアセンブリを、どれだけスタートアップで起動できるかが鍵みたいです。

    2010年1月18日 4:54
    モデレータ
  • どうやらシステムで使うアセンブリを、どれだけスタートアップで起動できるかが鍵みたいです。

    ひらぽんさんの実験結果、参考になります。
    ありがとうございます。

    今回の実験は、ダミーアプリで使用するディスクリソースがキャッシュメモリにキャッシュされ、本アプリで起動するときはディスクから読まずにキャッシュメモリから読み込まれるから、こんなにも速くなった、という解釈でよいのでしょうか。

    CLR 徹底解剖: アプリケーションの起動パフォーマンスを向上させる
    http://msdn.microsoft.com/ja-jp/magazine/cc337892.aspx


    2010年1月21日 6:58
  • 初めて、.NET ランタイムが初期化されるときに、こOS 全体にグローバルな AppDomain が2つ作成されるとされています。この初期化時間がかなりかかるので、前述の投稿のようにスタートアップに Main() 関数だけの空プログラムを配置しておくことで事前に初期化をしてしまえます。

    OS 全体にグローバルなのでしょうか?


    JIT and Run: .NET Framework の内部: CLR がランタイム オブジェクトを作成するしくみ -- MSDN Magazine, 2005 年 5 月
    http://www.microsoft.com/japan/msdn/msdnmag/issues/05/05/JITCompiler/default.aspx


    記事を読んでの解釈ですが、OS 全体にグローバルなのではなく、そのプロセス内に存在するアプリケーションドメイン全体にグローバルなのかな?と思いました。

    明確にしておきたい点は、「別プロセスだとそれぞれに System Domain と Shared Domain は存在するんだよね?」という点です。
    2010年1月21日 7:20
  • どうやらシステムで使うアセンブリを、どれだけスタートアップで起動できるかが鍵みたいです。

    う~ん、本当にそうなんでしょうか?ここまで上がった資料を斜め読みしてみると、なんだかディスク キャッシュに乗っているから速くなる、という気がしてきました。

    あ、「本当に」というのは、ここでは「いつまでも」という意図です。スタートアップで起動させておくと速くなるのはディスク キャッシュに乗るからで、スタートアップで起動・終了してから長時間使用せず、キャッシュの内容がその他のファイルに置き換わってしまえば、やっぱり遅くなるのでは?

    もし、「ディスク キャッシュに乗っているから速い」のであれば、対策としては、こんな感じ?
    スタートアップで常駐させるが、フォームは表示しない。
    メニューから起動要求があると、すでに起動しているプロセスを探す。
    プロセスが見つかれば、それに対して「表示」のメッセージを送り、新しいプロセスは終了する。
    プロセスが見つからなければ、自身でフォームを表示する。
    終了するときは、「非表示」になる。
    Windows から、ログオフやシャットダウンのメッセージを受け取ったときは、終了する。


    Jitta@わんくま同盟
    2010年1月22日 11:04
  • 皆様、ご回答いただきありがとうございます。
    いろいろと資料もあるようですので、こちらを読ませていただき、
    いろいろと試してみたいと思います。

    もし進展がありましたらご報告させていただきますので、
    よろしくお願いいたします。

    2010年1月29日 4:17