こんにちは、配列がいくつまで取得できるのか計算するマクロを作っている時に変なことに気が付きました。
エクセルでフォームとラベルを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も見ています
-
プロが教える店舗&オフィスのセキュリティ対策術
中・小規模の店舗やオフィスのセキュリティセキュリティ対策について、プロにどう対策すべきか 何を注意すべきかを教えていただきました!
-
VBA ReDim と ReDim Preserve の速度差
Visual Basic(VBA)
-
EXCEL VBA マクロ 実行する度に処理速度がどんどん遅くなる原因が知りたい
Excel(エクセル)
-
VBAの配列サイズとメモリに関して
Visual Basic(VBA)
-
-
4
VBAでループ内で使う変数名を可変にできないか。
Visual Basic(VBA)
-
5
配列でデータが入っている要素を求める方法
Visual Basic(VBA)
-
6
エクセルVBA 大容量CSVファイルの読み込みが遅い
Visual Basic(VBA)
-
7
エクセルVBA 配列からセルに「関数式」を一気代入したい
Visual Basic(VBA)
-
8
エクセルVBA Unionはなぜ遅い?
Visual Basic(VBA)
-
9
VBAでブックを非表示で開いて処理して閉じる方法
Excel(エクセル)
-
10
array関数で格納した配列の型を変更する
Visual Basic(VBA)
-
11
VBでファイルが開かれているかどうかを確認したい
Visual Basic(VBA)
-
12
〔Excel:VBA〕マクロの実行が異常に遅くなる
Excel(エクセル)
-
13
Excel VBAが徐々に遅くなる
Excel(エクセル)
-
14
フレーム内のオプションボタン状態取得方法について
Excel(エクセル)
-
15
配列をEraseしてもメモリが開放されていない?
Visual Basic(VBA)
-
16
VBA 変数名に変数を使用したい。
Visual Basic(VBA)
-
17
VBA データ(特定値)のある最終行を取得したい
Excel(エクセル)
-
18
VBAで保存しないで閉じると空のBookが残る
Excel(エクセル)
-
19
VBA 1次元配列を2次元に追加する
Visual Basic(VBA)
-
20
VBAでワークシートを引数としてサンプル関数に渡したい
Visual Basic(VBA)
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
VBA 変数名に変数を使用したい。
-
コンボボックスのインデックス...
-
エクセルでXY座標に並べられた...
-
C#でbyte配列から画像を表示さ...
-
構造体配列の特定のメンバーをF...
-
配列の要素がすべてカラかどう...
-
配列の中の最大値とそのインデ...
-
Redim とEraseの違いは?
-
Excelマクロ:配列データからグ...
-
C言語 ポインタと配列
-
vba フィルター 複数条件 3つ以...
-
CheckBoxの配列化
-
VBで重複しているデータをユニ...
-
エクセルVBAからNotesでメー...
-
エクセルの列一括書き込み
-
定数配列の書き方
-
エクセル(VBA)の空白配列の削除...
-
DBから取得した値を配列へ代入する
-
配列の中から最大値だけ取り出...
-
pictureboxの名前を変数で設定...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBA 変数名に変数を使用したい。
-
Excel2010のinputboxで複数デー...
-
vba フィルター 複数条件 3つ以...
-
C#でbyte配列から画像を表示さ...
-
配列のペースト出力結果の書式...
-
Dir関数で読み取り順を操作でき...
-
エクセルでXY座標に並べられた...
-
VBAで配列引数を値渡しできない...
-
C++で作成したDLLにVBAから配列...
-
構造体配列の特定のメンバーをF...
-
OutOfMemoryExceptionの回避策...
-
大量の変数を定義するにはどう...
-
VBAでMODE関数をつくる
-
VBScriptでCSVファイルを読み出...
-
定数配列の書き方
-
Segmentation Fault (メモリ制限?)
-
Excelのメモリ(配列)の上限は2G...
-
Redim とEraseの違いは?
-
CheckBoxの配列化
-
配列の中の最大値とそのインデ...
おすすめ情報