
こんにちは、配列がいくつまで取得できるのか計算するマクロを作っている時に変なことに気が付きました。
エクセルでフォームとラベルを1つ用意し、下記のようなプログラムをモジュールに書きます。
実行すると、10万ずつ数字が増えていき、数字が1000~2000万超えたあたりで、メモリ不足ですという
表示がでます。
ここで、ReDim PreserveのPreserveをとって、ReDimだけにすると、数字の増え方が目に見えて遅くなります。
ReDim Preserveとしたときは9.5秒ぐらいですが
ReDim の時は 30秒以上かかっています
3台のマシンでテストしましたが、どれも似たような結果になりました
普通に値を保持するredim Preserveの方が遅いと思うのですがなぜこのような結果になるのでしょうか?
ご教授お願いいたします。
Public Sub 配列上限取得計算()
On Error GoTo ErrEnd
Dim i As Long
Const kankaku As Long = 100000
ReDim ans(1 To kankaku) As String
ans(1) = 1
i = 2
UserForm1.Show vbModeless
Do
If i Mod kankaku = 0 Then
DoEvents
UserForm1.Label1 = i
'ここのPreserveをなくすと明らかに遅くなる
ReDim Preserve ans(1 To i + kankaku) As String
End If
ans(i) = i
i = i + 1
Loop
Erase ans
Unload UserForm1
Exit Sub
ErrEnd:
MsgBox "これ以上の配列を設定できません。" & vbCrLf & "上限は" & i & "です。" & vbCrLf & Err.Description
Erase ans
Unload UserForm1
End Sub
No.1ベストアンサー
- 回答日時:
こんにちは、
> ここで、ReDim PreserveのPreserveをとって、ReDimだけにすると、数字の増え方が目に見えて遅くなります。
> ReDim Preserveとしたときは9.5秒ぐらいですが
> ReDim の時は 30秒以上かかっています
ReDim は 新築
ReDim Preserve は 増築
という喩で説明になっているかと思います。
実際には、Eraseして、メモリの再割り当てをしつつ、配列のサイズ(ディメンション)を再定義するのがReDim
既存のメモリを維持しつつ、メモリを拡張、サイズを再定義するのがReDim Preserve
ということになります。
必然的にReDimを繰り返したら遅くなります。
ご提示のコードでPreserve キーワードを抜くと、
kankakuごとに、ReDimしている訳ですから、
せっかく格納したそれまでの値を消去していることになります。
可変長のString型変数の場合は特殊で、割り当てられるメモリサイズが固定ではありませんから
格納したり消去(長さ0の文字列を格納)したりするのに特に時間が掛かります。
ご提示のコードでPreserve キーワードを抜くと、
それまでに格納した文字長に比例したメモリサイズ、は無視されてしまいます。
本来の目的から外れたテストになってしまいます。
可変長の変数なのですから、要素数、だけではなくて、
要素数と文字長、の2点について、色々パラメータを変えながら
テストしてみた方がより有意義なものになるのではないかと思います。
Dim ans() As String
のように一旦、文字列型として、動的配列変数を予め定義しておいた方が
テストの精度が高まりますし、ReDimに掛かる時間も短くなります。
以上です。
詳しい解説をありがとうございます
>>可変長のString型変数の場合は特殊で、割り当てられるメモリサイズが固定ではありませんから
格納したり消去(長さ0の文字列を格納)したりするのに特に時間が掛かります。
ここで納得できました。試しにstringでlongにしてみると、普通のredimでも高速になりましたし、string型のときに要素数が増えれば増えるほどだんだん遅くなっていったのも、redimする度にすべての要素に長さ0の文字列を格納していたせいだと考えると、つじつまがあいます。
>>可変長の変数なのですから、要素数、だけではなくて、
要素数と文字長、の2点について、色々パラメータを変えながら
テストしてみた方がより有意義なものになるのではないかと思います。
その通りですね。ただ、実際にパラメータを変えてトライしてみたら、新たな疑問が発生してしまったんですが、この質問自体はもう答えてもらってるので、新しい質問として載せることにします。
ありがとうございました
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) Dateserialで データ抽出 2 2022/06/26 21:07
- Excel(エクセル) Excelにて、フォルダ内のTextファイルをマクロで統合すると文字化けしてしまう時の解消コード 4 2023/01/01 07:32
- Visual Basic(VBA) ExcelVBAで質問です。離れた二次元配列を一つにしたい 4 2022/07/26 19:06
- Visual Basic(VBA) userformでSheetを選択して開くコード 1 2023/05/15 16:27
- Visual Basic(VBA) ①ExcelVBAでカレンダーを作り、別のユザーフォームで日付を入力したいのですがエラーになります。 1 2023/02/17 18:39
- Visual Basic(VBA) EXCEL VBAにて動的にCheckBOXを複数作成し、同BOXにイベントを追加したい 1 2023/03/16 07:05
- Visual Basic(VBA) ExcelVBAに関する質問 3 2023/02/17 10:47
- Visual Basic(VBA) いつもお世話になっております、VBAで教えて頂きたいのですが 2 2022/05/05 22:20
- Visual Basic(VBA) InputBoxでキャンセルボタンを押したらファイル自体を閉じたい 3 2022/07/23 17:52
- Visual Basic(VBA) 稀に1円合いません? Sheet1から金額と個数を貼り付ける下記コードで、金額を切り上げるコードを何 3 2022/09/05 15:11
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
配列の中の最大値とそのインデ...
-
VBA 変数名に変数を使用したい。
-
EXCELを使って、アクセスログを...
-
Dir関数で読み取り順を操作でき...
-
Excel2010のinputboxで複数デー...
-
VBScriptでCSVファイルを読み出...
-
C#でbyte配列から画像を表示さ...
-
VB6のメモリ解放に関して
-
バイナリエディタ
-
定数配列の書き方
-
VB.NETの配列にExcelから読み込...
-
レコードセットの中身を配列に...
-
配列の中から最大値だけ取り出...
-
エクセルの列一括書き込み
-
VBで組み合わせのプログラム...
-
VBでの配列をEXCELに出力する方法
-
c++ 乱数生成について
-
VBAにて、配列のデータを一度に...
-
空白を埋めるマクロについて
-
C#で作成したdllをVBScriptで使...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBA 変数名に変数を使用したい。
-
vba フィルター 複数条件 3つ以...
-
C#でbyte配列から画像を表示さ...
-
Dir関数で読み取り順を操作でき...
-
エクセルでXY座標に並べられた...
-
配列のペースト出力結果の書式...
-
定数配列の書き方
-
大量の変数を定義するにはどう...
-
構造体配列の特定のメンバーをF...
-
Redim とEraseの違いは?
-
複数のtextboxの処理を一括で行...
-
VB.NETの配列にExcelから読み込...
-
COBOLの基本的な事なので...
-
Excel2010のinputboxで複数デー...
-
VBAでMODE関数をつくる
-
レコードセットの中身を配列に...
-
ReDim PreserveよりもReDimが遅い
-
EXCELを使って、アクセスログを...
-
配列の中の最大値とそのインデ...
-
VB6のメモリ解放に関して
おすすめ情報