- PR -

Windowsアプリの起動時間、どれくらいかかってますか?

投稿者投稿内容
やんたん
ベテラン
会議室デビュー日: 2003/08/18
投稿数: 63
投稿日時: 2005-04-06 12:54
お世話になります。

.NETで作成したWindowsアプリケーションは起動に時間がかかり、OS起動後最初にそのアプリケーションを動かした時特に遅いというところまでは各種サイトや計測を行ったので把握できています。(2回目以降のアプリケーション起動は格段に早いです)
そこで下記のコードのような非常にシンプルなWindwosアプリケーションを作成し
10台程度の端末で起動時間を計ってみました。
(ここで言う起動時間とは、exeファイルをダブルクリックしてからMainの最初のコードが実行されるまでのことを指しています)

10台で下記アプリを実行して起動時間を検証した結果、平均して3秒程度かかっています。
かなり遅いと思っているのですが、みなさまの環境でもこんなもんなんでしょうか?
もしよかったら試してレポートして頂けると助かります。
また、下記のような単純なアプリで3秒もかかっていると、とても実用に耐えれないと思うのですが、みなさんこのあたりなんらかの対策ってされてますか?
(こういう話をすると、ngenの話が出てくると思いますが、あれって効果が出るかは
 端末に依存するといったことをどこかのサイトで見た気がします。
 実際にご利用経験のある方がいらしたら、是非情報提供して欲しいです!)

もし実際に下記コードを動かしてくれる方がいらした場合に、私が行った
計測方法を書いておきます。
@OSを再起動
AOS起動後、ある程度落ち着くまでまつ
Bシステム時間を見ながら下記アプリを起動
C起動させた時間をアプリに表示された時間の差が起動時間

なぜBのような原始的な方法をとったかといいますと、タスクに登録してアプリを
実行して計測してたのですが、それだと起動に40秒もかかってしまう端末が出て
きたりしたので上記のような計測方法を取っています。
バッチからの起動も考えたのですが、同様の現象が起こるとイヤなので
原始的な方法で計測してます。

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WindowsApplication1
{
/// <summary>
/// Form1 の概要の説明です。
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;

private static DateTime g_dt;

/// <summary>
/// 必要なデザイナ変数です。
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Windows フォーム デザイナ サポートに必要です。
//
InitializeComponent();

//
// TODO: InitializeComponent 呼び出しの後に、コンストラクタ コードを追加してください。
//
}

/// <summary>
/// 使用されているリソースに後処理を実行します。
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows フォーム デザイナで生成されたコード
/// <summary>
/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
/// コード エディタで変更しないでください。
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.Location = new System.Drawing.Point(16, 16);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(264, 23);
this.label1.TabIndex = 0;
this.label1.Text = "label1";
//
// label2
//
this.label2.Location = new System.Drawing.Point(16, 40);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(264, 23);
this.label2.TabIndex = 1;
this.label2.Text = "label2";
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main()
{
g_dt = DateTime.Now;

Application.Run(new Form1());
}

private void Form1_Load(object sender, System.EventArgs e)
{
DateTime dt = DateTime.Now;

label1.Text = g_dt.ToString("yyyy-MM-dd HH:mm:ss.") + g_dt.Millisecond.ToString("000");
label2.Text = dt.ToString("yyyy-MM-dd HH:mm:ss.") + dt.Millisecond.ToString("000");
}
}
}
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2005-04-06 13:24
ぼのぼのです。
やんたんさん、こんにちわ。

私も以前、毎日最初に行う定型的な手作業を簡易化するために、特定の文字列をクリップボードにコピーするだけのごくごく簡単な自作ツールをVB.NETで作ってスタートアップに入れといたのですが、あまりに起動が遅くてMFCで作り直したことがあります。

で、なぜ.NETで作ったものがVC++で作ったものに比べて初回起動が遅いかという理由は、下記リンクの2章、3章あたりが参考になるかもしれません。

.NET Framework入門

<追記>
引用:

また、下記のような単純なアプリで3秒もかかっていると、とても実用に耐えれないと思うのですが、みなさんこのあたりなんらかの対策ってされてますか?


ここを読み飛ばしちゃってました。自分で使うツールについては上記の通りです。仕事ではWebをやってて、仕事としてのWindowsアプリはやったことないんですが、私だったらまずこういう背景があって初回だけは起動が遅くなってしまうけどプログラムのせいではないということ、そして.NETはそれ以上の恩恵(所謂DLL地獄からの解放ってやつですね)を与えてくれますよ、みたいなことを言って顧客を説得してみます。顧客にもよりますが、きっちりした技術的な理由があると結構納得してもらえます。それで納得してもらえなかったら、初めて対策を考えます。

[ メッセージ編集済み 編集者: ぼのぼの 編集日時 2005-04-06 14:04 ]
やんたん
ベテラン
会議室デビュー日: 2003/08/18
投稿数: 63
投稿日時: 2005-04-06 14:23
ぼのぼのさん、早速のお返事ありがとうございます!

参考情報(URL)のご提示ありがとうございます。
ただ、この起動時間の問題についてかなり長期間悩んでますので
そのあたりの情報はかなり熟読させていただいています。
そんな中、ふとみなさんは同様の課題にぶつかっていないのか。
ぶつかっているならどのように解決しているのかを聞いてみたくて投稿させて頂きました。

引用:
私だったらまずこういう背景があって初回だけは起動が遅くなってしまうけどプログラムのせいではないということ、そして.NETはそれ以上の恩恵(所謂DLL地獄からの解放ってやつですね)を与えてくれますよ、みたいなことを言って顧客を説得してみます。顧客にもよりますが、きっちりした技術的な理由があると結構納得してもらえます。それで納得してもらえなかったら、初めて対策を考えます。



おっしゃるとおりだと思います。
ただ、私の場合はちょっとややこしいことになってまして顧客調整は困難なんです。
(起動モジュールの共通部品のようなものを提供しており、それを複数のシステムで使っています。ですので、幅広い顧客への調整は現実不可能なんです。)
なにより、やはり調整ではなく技術で解決したいじゃないですか

引き続き、みなさんの体験談や以前ご提示させて頂いたモジュールで検証して頂いた方がいらしたらその結果報告をお待ちしております
kanai
ベテラン
会議室デビュー日: 2004/09/13
投稿数: 98
投稿日時: 2005-04-06 14:27
引用:

(こういう話をすると、ngenの話が出てくると思いますが、あれって効果が出るかは
 端末に依存するといったことをどこかのサイトで見た気がします。
 実際にご利用経験のある方がいらしたら、是非情報提供して欲しいです!)



私は下記の記事を読んで、ngenで事前にJITコンパイルすれば初回起動も早くなるもの、
と信じていましたが、そうではないのでしょうか?

http://www.atmarkit.co.jp/fdotnet/vbcheer/vbcheer08/vbcheer08.html

「ngenで初回起動が早くなるかどうか?」も検証されてはいかがでしょうか?

やんたん
ベテラン
会議室デビュー日: 2003/08/18
投稿数: 63
投稿日時: 2005-04-06 14:45
kanaiさん、お返事ありがとうございます。

ngenの件、アドバイスありがとうございます。
私の書き込みに情報が不足しておりました。
ngenについては検証してみたのですが
(少なくとも私の端末では)効果がありませんでした。
なぜ、「私の端末では」なのかというと、下記サイトに以下のような情報があります。

引用:
アプリケーションの起動時間には多くの要因が影響を及ぼすため、Ngen.exe を使用することでパフォーマンスが向上するアプリケーションはどれかを注意深く検討する必要があります。検討対象のアセンブリの JIT コンパイル バージョンとプリコンパイル バージョンの両方を、そのアセンブリが実行される環境で実行して実験します。この方法で、同じアセンブリを異なるコンパイル方法で実行した場合の起動時間を比較できます。
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cptools/html/cpgrfnativeimagegeneratorngenexe.asp


また、これは情報ソースがどこだったか忘れてしまいましたが、ngenよりJITコンパイラの方が最適にコンパイルを行ってくれるため、場合によっていはパフォーマンスが悪化するというのを聞いたこともあります。

このように、パフォーマンスが良くなるか悪くなるかがわからないものを適応するのは難しいと思っています。
実際、ngenを適応しているアプリケーションってあるんでしょうかねぇ?

引き続き、みなさまの様々な体験談をお聞かせ下さい
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2005-04-06 18:41
ぼのぼのです。
おもしろそうだったんで、こんなん作ってみました

コード:

●VC.exe(Visual C++プロジェクト Win32 コンソール プロジェクト)
#include "stdafx.h"
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
//現在時刻をファイルに記述
FILE *fp;
fp = fopen("C:\\Temp\\StartupTime.log", "w");
if(fp == NULL) {
printf("file open failed.");
return 1;
}
SYSTEMTIME st;
GetLocalTime(&st);
fprintf(fp,"%d/%02d/%02d %02d:%02d:%02d.%03d\n",
st.wYear, st.wMonth, st.wDay,
st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
fclose(fp);

//C#で作ったexeを実行
ShellExecute(NULL, NULL, "CS.exe", NULL, ".", SW_SHOWNORMAL);

return 0;
}

●CS.exe(Visual C#プロジェクト Windowsアプリケーション)
[STAThread]
static void Main()
{
//現在時刻をファイルに追加
System.IO.StreamWriter w = new System.IO.StreamWriter(
"C:\\Temp\\StartupTime.log", true,
System.Text.Encoding.GetEncoding("Shift_JIS"));
w.WriteLine(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff"));
w.Close();

Application.Run(new Form1());
}


もしやんたんさんが自分のホームページ等お持ちでしたら、
コンパイル済みのexeをそこからダウンロードできるようにすれば、
皆さんもっと気軽に協力できるんではないでしょうか
まぁ最終目的は速くすることで、データを集めることではないんでしょうけど…

ちなみに私のマシンでの実行結果は
1回目
2005/04/06 18:16:19.140
2005/04/06 18:16:30.750
2回目
2005/04/06 18:16:45.421
2005/04/06 18:16:45.765
です。相当違いますねぇ…
#ちなみに1回目はOS再起動直後

[ メッセージ編集済み 編集者: ぼのぼの 編集日時 2005-04-06 18:48 ]
Jubei
ぬし
会議室デビュー日: 2002/03/02
投稿数: 830
お住まい・勤務地: 関西
投稿日時: 2005-04-06 19:15
引用:

おもしろそうだったんで、こんなん作ってみました:D


私も面白そうだったので、こんなの作りました(^^;
計測アプリは二つです。
一つはSystem.Diagnostics.Process.Start()を使って起動時間(呼び出し時間)を引数で渡します。受け取った側はForm_Loadイベントの中で自分の起動完了(に近い時間)と受け取った時間をラベルに表示、ついでにログに記録です。

コード:
//--呼出側--
//フォームにLabel×1とButton×2、OpenFileDialogを配置

private void Form1_Load(object sender, System.EventArgs e)
{
    label1.Text = "";
}

private void button1_Click(object sender, System.EventArgs e)
{
    openFileDialog1.Filter = "exe|*.exe";
    openFileDialog1.InitialDirectory = Application.StartupPath;
    if (openFileDialog1.ShowDialog() == DialogResult.OK)
    {
        label1.Text = openFileDialog1.FileName;
    }
    else
    {
        label1.Text = "";
    }
}

private void label1_TextChanged(object sender, System.EventArgs e)
{
    Label l = sender as Label;
    if (l != null)
    {
        button2.Enabled = l.Text.Length > 0;
    }
}

private void button2_Click(object sender, System.EventArgs e)
{
    DateTime start = DateTime.Now;
    string startStr = 
        string.Format("起動開始時間は{0}時{1}分{2}秒{3}ミリ秒",
            start.Hour,start.Minute,start.Second,start.Millisecond);
    System.Diagnostics.Process.Start(label1.Text,startStr);
}

//--呼び出され側--
//フォームにLabel×2を配置

private void Form1_Load(object sender, System.EventArgs e)
{
    DateTime dt = DateTime.Now;
    label2.Text = 
        string.Format("表示完了は{0}時{1}分{2}秒{3}ミリ秒",
            dt.Hour,dt.Minute,dt.Second,dt.Millisecond);

    string[] args = System.Environment.GetCommandLineArgs();
    if ((args != null) && (args.Length > 1))
    {                                       
        label1.Text = args[1];   
    }
    
    string logPath = System.IO.Path.Combine(Application.StartupPath,"mylog.log");
    using (System.IO.StreamWriter sw = new System.IO.StreamWriter(logPath,true))
    {
        sw.WriteLine(label1.Text);
        sw.WriteLine(label2.Text);
        sw.WriteLine();
    }
}




引用:

ちなみに私のマシンでの実行結果は
1回目
2005/04/06 18:16:19.140
2005/04/06 18:16:30.750
2回目
2005/04/06 18:16:45.421
2005/04/06 18:16:45.765
です。相当違いますねぇ…
#ちなみに1回目はOS再起動直後



こちらでの計測結果は次の通りです。
どれも、OS起動直後、安定稼働(?)したようなところで計測開始しています。
見る限りでは、数秒掛かるというのが無いですね。。

----
CPU:P3 900MHz
MM:512MB
OS:WinXP PRO SP2
----
起動開始時間は18時56分26秒456ミリ秒
表示完了は18時56分27秒698ミリ秒

起動開始時間は18時56分37秒752ミリ秒
表示完了は18時56分38秒133ミリ秒

起動開始時間は18時56分39秒204ミリ秒
表示完了は18時56分39秒555ミリ秒

起動開始時間は18時56分40秒606ミリ秒
表示完了は18時56分40秒987ミリ秒

起動開始時間は18時56分41秒587ミリ秒
表示完了は18時56分41秒968ミリ秒

起動開始時間は18時56分44秒882ミリ秒
表示完了は18時56分45秒263ミリ秒

起動開始時間は18時56分47秒466ミリ秒
表示完了は18時56分47秒846ミリ秒

----
CPU:P4 3.4GHz
MM:2GB
OS:WinXP PRO SP2
----
起動開始時間は18時49分11秒500ミリ秒
表示完了は18時49分11秒859ミリ秒

起動開始時間は18時49分14秒46ミリ秒
表示完了は18時49分14秒375ミリ秒

起動開始時間は18時49分15秒875ミリ秒
表示完了は18時49分16秒203ミリ秒

起動開始時間は18時49分17秒468ミリ秒
表示完了は18時49分17秒750ミリ秒

起動開始時間は18時49分19秒93ミリ秒
表示完了は18時49分19秒375ミリ秒

起動開始時間は18時49分20秒968ミリ秒
表示完了は18時49分21秒234ミリ秒

起動開始時間は18時49分22秒828ミリ秒
表示完了は18時49分23秒93ミリ秒

----
CPU:P4 1.6GHz
MM:1GB
OS:Windows Server 2003
----
起動開始時間は19時9分50秒442ミリ秒
表示完了は19時9分50秒702ミリ秒

起動開始時間は19時9分54秒248ミリ秒
表示完了は19時9分54秒418ミリ秒

起動開始時間は19時9分56秒90ミリ秒
表示完了は19時9分56秒270ミリ秒

起動開始時間は19時9分57秒933ミリ秒
表示完了は19時9分58秒113ミリ秒

起動開始時間は19時9分59秒635ミリ秒
表示完了は19時9分59秒806ミリ秒

起動開始時間は19時10分1秒808ミリ秒
表示完了は19時10分1秒989ミリ秒

起動開始時間は19時10分3秒982ミリ秒
表示完了は19時10分4秒152ミリ秒


_________________
諸農和岳
Powered by Turbo Delphi & Microsoft Visual Studio 2005

十兵衛@わんくま同盟
http://blogs.wankuma.com/jubei/
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2005-04-06 20:25
ぼのぼのです。
私、実行環境のマシンスペック書いてませんでしたね。
----
CPU:Celeron 2.00GHz
MM:512MB
OS:Win2K Server SP4
----
です。

引用:

Jubeiさんの書き込み (2005-04-06 19:15) より:
こちらでの計測結果は次の通りです。
どれも、OS起動直後、安定稼働(?)したようなところで計測開始しています。



私、安定稼働(?)しないうちに計測開始しちゃったかも…
というわけで測りなおしました。

2005/04/06 20:07:56.796
2005/04/06 20:08:05.281

やはりずいぶん掛かります…

引用:

見る限りでは、数秒掛かるというのが無いですね。。


なんでJubeiさんの結果とこんなに違うのか?何か差があるのか?
すぐにテストツールに大きな差があることに気づきました。
それは、Jubeiさんのテストツールは呼出側も.NETで実装していることです。

そこで、マシンをもいっかい再起動して、
今度はCS.exeとは全然関係ないVB.NETで作ったWindowsアプリを実行してから、
テストツールを実行してみました。結果は以下の通り。

2005/04/06 20:15:05.968
2005/04/06 20:15:06.953

1秒かかってません。
どうも.NET Frameworkそのものが、最初のexeがキックされた時点で、
準備みたいなもの(?)をしている感じです。

[ メッセージ編集済み 編集者: ぼのぼの 編集日時 2005-04-06 20:25 ]

スキルアップ/キャリアアップ(JOB@IT)