VBA性能向上委員会

VBAプログラミングの実行速度に関して、より速い性能を求めて徹底検証をします。


HOME > VBA性能徹底検証 > いつNewする?変数宣言時でしょ!

いつNewする?変数宣言時でしょ!

なんだか「今でしょ」みたいなタイトルですね。

結論から言うと「Newは変数宣言時にしましょう」というお話です。


オブジェクト変数やクラス変数を作成するには、Newキーワードを使いインスタンスを生成する必要があります。


このNewキーワードは、『変数を宣言したとき』または『オブジェクトを参照させるとき』に使用します。

次のサンプルをご覧ください。

基本的には2つのうちどちらかで処理を書くと思います。


' Newキーワードの使い方 サンプル1『変数を宣言したとき』
Dim obj As New Collection

' Newキーワードの使い方 サンプル2『オブジェクトを参照させるとき』
Dim obj As Collection
Set obj = New Collection

さて、この2つの書き方は、どちらを書けば良いでしょうか?

性能の検証をしてみましょう。


今回はただ2つのパターンだけではつまらないので、さらに、Object宣言をしてからNewする方法についても併せて検証してみたいと思います。



検証用サンプルプログラム

今回は3つのパターンを用意しました。


1.変数宣言時にNew サンプルプログラム

Sub 変数宣言時にNew()
Dim obj As New Collection
Set obj = Nothing
End Sub

2.変数宣言してからNew サンプルプログラム

Sub 変数宣言してからNew()
Dim obj As Collection
Set obj = New Collection
Set obj = Nothing
End Sub

3.Object宣言してからNew サンプルプログラム

Sub Object宣言してからNew()
Dim obj As Object
Set obj = New Collection
Set obj = Nothing
End Sub


検証

上記3つのパターンについての実行結果は次の通りです。

1,000,000回ループで検証しています。


回数変数宣言時にNew変数宣言してからNewObject宣言してからNew
1回目0.1530.7090.698
2回目0.1510.7070.700
3回目0.1520.7080.698
4回目0.1520.7060.699
5回目0.1520.7050.701
6回目0.1530.7070.700
7回目0.1540.7060.698
8回目0.1530.7050.699
9回目0.1520.7050.700
10回目0.1530.7070.702
平均0.1530.7070.700

※単位は全て『秒』


結果は一目瞭然です。

変数宣言時にNewをする方法が圧倒的に早いことがわかります。


どうしてこんなに差がついてしまうのでしょうか?

実はその答えはMicrosoft Visual Basic のヘルプに書いてあります。



New 省略可能です。このキーワードを指定すると、オブジェクトを暗黙的に作成できます。オブジェクト変数を宣言するときにキーワード New を指定した場合は、オブジェクトを最初に参照したときにオブジェクトの新しいインスタンスが作成されるので、Set ステートメントを使ってオブジェクトへの参照を代入する必要はありません。

[ Microsoft Visual Basic のヘルプ - Dim ステートメントより引用 ]


変数宣言時にNewをしただけではインスタンスは作られず、そのオブジェクトに初めてアクセスしたときにインスタンスが作られる。と書いてあります。

ステップ実行で見てみるとわかります。以下画像をご覧ください。


オブジェクト変数またはWithブロック変数が設定されていません。

つまり先ほどの検証では明らかに公平な検証を行っていないことになります。

これは意外と落とし穴です!なので、もう一度検証を行ってみましょう。



検証用サンプルプログラム 2回目

インスタンスを作るために、オブジェクトにアクセスをしてみましょう。


Newした後にCountを呼んでみます。

obj.Countのところですね。


1.変数宣言時にNew サンプルプログラム (改良版)

Sub 変数宣言時にNew()
Dim obj As New Collection
obj.Count
Set obj = Nothing
End Sub

2.変数宣言してからNew サンプルプログラム (改良版)

Sub 変数宣言してからNew()
Dim obj As Collection
Set obj = New Collection
obj.Count
Set obj = Nothing
End Sub

3.Object宣言してからNew サンプルプログラム (改良版)

Sub Object宣言してからNew()
Dim obj As Object
Set obj = New Collection
obj.Count
Set obj = Nothing
End Sub


検証 2回目

さて、2回目の検証では実行結果はどうなっているでしょうか?

結果は次の通りです。


回数変数宣言時にNew変数宣言してからNewObject宣言してからNew
1回目0.7730.7323.064
2回目0.7280.7303.062
3回目0.7260.7323.068
4回目0.7260.7303.063
5回目0.7250.7303.072
6回目0.7270.7303.073
7回目0.7270.7353.068
8回目0.7270.7313.065
9回目0.7280.7343.089
10回目0.7270.7313.066
平均0.7310.7323.069

※単位は全て『秒』


変数宣言時にNewした場合と、変数宣言してからNewした場合とでは、処理速度に差は見られませんでした。

ということはインスタンスを生成する変数については、「変数を宣言する際に(どうせ必ずNewするのだから)Newと書いておく」か、「Newするタイミングを明記したいのでSetステートメントを使う」かのどちらか理由で使い分ければ良いのでしょう。


ちなみにObject宣言をした場合に処理速度が遅いのは、最初に作られる変数の領域と次に作られる変数の領域が異なるため、「変数を作り直す」という処理が実行されるためです。

「無駄にキャスト処理を行っている」と言えますね。


今回の検証では、実行速度についてもそうですが、インスタンスの生成タイミングについても大事なポイントがわかりました。

処理のタイミングで使用しているメモリを把握して、性能向上を図りたいものですね。