
すみません。一度質問を載せた後で、補足で絵を載せようとしたのですができなかったので
再投稿させていただきます。(元の質問はけしました。)
--------------------------------------
こんにちは、今作成しているエクセルのVBAで配列を膨大に食ってしまい、メモリ不足に落ちいるという現象に悩まされています。
そのため、なるべくいらなくなった配列はEraseステートメントを使って解放しようとしてるのですが、
これが上手くいっている気がしません。
ためしにフォームと、ラベルを1つずつ用意し、下記のような配列をどこまで作れるか計算するプログラムを組んでみました。
1回目、ans(i) に"a"というaを1個のみ格納した場合で計算すると、配列は2970万個できます。
2回目、ans(i) に"aaa~a"というaを64個格納した場合で計算すると、配列は770万個できます。
まぁ、ここまでは当然の結果だと思います。
可変長のString型変数の場合は、割り当てられるメモリサイズが固定ではないらしいので
(前回の質問で教えてもらいました)
しかし3回目、ここでもう一回、1回目と同じ、"a"を一個のみ格納した場合で計算してみます。
私の予想では1回目と同じ2970万個程度の配列が作れると思っていました。
なぜなら、Eraseステートメントでメモリを解放していたし、
タスクマネージャーのPF使用量(おそらくメモリの値)を見ても2回目を実行した後の値は
1回目前と同じ値に戻っているからです。
しかし、実際試してみると、
2回目と同じ770万個の配列しかつくれませんでした。
つまり、Eraseステートメントを使用しても配列の上限値は元の状態に戻らなかったのです。
どうすれば、配列を再び2970万個作れる初期の状態に戻せるのでしょうか?
現時点ではエクセルを起動しなおせば、元に戻りますが、それでは困ります
(プログラムの途中で配列の数を減らしたり、コピーしたりを行っている為、
どうしてもプログラム中でメモリの解放を行いたいからです)
また、添付した絵は、実行した時のタスクマネージャーの様子です。
参考になれば幸いです
どうか、みなさんお知恵をお貸ししてください
---------------------------------------------------
'実行するときは、フォームとラベルを1つずつ用意して実行してください
Public Sub 配列上限取得計算()
On Error GoTo ErrEnd
Dim i As Long
Const kankaku As Long = 100000
Dim ans() As String
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
ReDim Preserve ans(1 To i + kankaku) As String
End If
'最初にaを1個のみ格納した場合は、2970万個まで配列が作れるが、次にaを64個格納した場合は770万個まで作れた。
'しかし、その直後にまた、aを1個のみ格納した場合で実行してみると、770万個しか作れない
'つまり、Eraseステートメントを使っているにも関わらず、同じ条件のプログラムでも配列の上限が下がってしまう。
'この現象をなんとか回避したい。元の状態にリセットするにはエクセルを起動しなおさないと直らない。
'1回目と3回目に実行するコード、2回目はコメントアウトしてください
ans(i) = "a"
'2回目に実行したコード、2回目はコメントアウトを解除してください。
' ans(i) = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
i = i + 1
Loop
Erase ans
Unload UserForm1
Exit Sub
ErrEnd:
Erase ans
MsgBox "これ以上の配列を設定できません。" & vbCrLf & "上限は" & i & "です。" & vbCrLf & Err.Description
Unload UserForm1
End Sub

No.2ベストアンサー
- 回答日時:
使用メモリが断片化して、2970万個分の連続領域が確保できない、というケースもありそうです。
初期化ですが、Excel再起動以外の方法は、私は知りません。
この回答への補足
そうですか・・・断片化と聞いて勝手に想像してみたのですが
"a"がアドレス一個分のメモリを消費
"aaaaaaa~a"がアドレス100個分のメモリを消費すると仮定した場合
最初に
a(0):001番地
a(1):002番地
a(2):003番地
といった具合だったのが
a(0):001~100番値
a(1):101~200番値
a(2):201~300番値
といった感じで、メモリのアドレスを占有するけれど
次に、"a"で格納しようとした場合、実際に使うのは1個分のアドレスだけど
a(0):001番値、002~100番地はデータのゴミ
a(1):101番値、102~200番地はデータのゴミ
a(2):201番値、202~300番地はデータのゴミ
という感じになって、002~100番地を有効に使えないようなイメージでしょうか。
どうにか解決策が知りたいです。
No.5
- 回答日時:
> BSTRキャッシュを無効というのは、String型以外にしろということでしょうか?
(用語の意味が分からないなら)ググらないと。
参考URL:http://keicode.com/com/bstr-cache.php
この回答への補足
すみません。ご親切にありがとうございます。
システム環境変数にOANOCACHE=1を追加して、PCを再起動してみましたが、特に変化は見られませんでした。
やはり、無理なのでしょうか
No.4
- 回答日時:
>そうですか、では、配列の上限値をもとの状態に戻すことは不可能なのでしょうか?
申し訳ありませんが可能かどうか私にはわかりません。
#2の方がいわれるように断片化が原因であるなら再起動するしか手はないと思いますが。
この回答への補足
なるほど、断片化が原因なら無理なんですね。
どうも、それっぽい感じもしますね。
NO2でちょっと勝手ながら断片化の解釈しちゃってますけど
あれだと、配列が同じ数だけしか作れない事の
つじつまがあいますし、Excelの再起動で直るわけですし。
そうなると、なるべく配列は減らして、影響を少なくなるように設計するしかなさそうですねぇ・・・
毎回マクロ実行するたびにexcel起動しなおさなければならないのもあれですが・・・
No.3
- 回答日時:
単にOSのキャッシュが効いてるだけでは。
BSTRキャッシュを無効にしてみるとか。
※ BSTR(VBAのString型の事)
この回答への補足
BSTRキャッシュを無効というのは、String型以外にしろということでしょうか?
残念ながら、扱う値は文字列なのです。
確かに、long型とかだと、値変えてもあまり変化ないですね。
string型だと可変長の長さを持っている為、
一度大きな文字列を入れてしまうと、文字列を後から入れなおしても
メモリの番地を詰めることができないということなんでしょうか・・・
文字列だと不可能なんですかね
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) VBA横データを縦にしたいです 2 2023/08/08 19:38
- Visual Basic(VBA) ファイル全てを .xlsm に変更したところ、プログラムが途中で落ちてしまっています 17 2022/12/07 12:03
- Visual Basic(VBA) 改行ごとに行を追加し、数量を分割 4 2023/07/11 16:39
- Visual Basic(VBA) 複数シートの複数列に入力されているデータを重複なしで抽出するVBAを作りたいです。 9 2022/06/17 10:33
- Excel(エクセル) VBAで組み合わせ算出やCOUNTIFSの処理を高速化したいです。 4 2022/04/07 02:38
- Visual Basic(VBA) VBAでのMATCH関数 3 2022/10/17 19:06
- Visual Basic(VBA) マクロVBA 1シートをまとめる 閉じ方 初心者 SOS! 1 2022/06/17 14:54
- Visual Basic(VBA) コード名シートA列と集計シートA列のコードが一致したら、コード名シートA5からk12の範囲をコピーし 1 2022/08/29 23:46
- Visual Basic(VBA) 別シートから年齢別の件数をカウントしたいの続き 5 2023/01/24 00:16
- Perl perl このテキストファイルを簡単に配列に入れるには? 2 2022/04/27 20:24
このQ&Aを見た人はこんなQ&Aも見ています
-
VBAの配列サイズとメモリに関して
Visual Basic(VBA)
-
Redimした動的配列はEraseする必要があるのか
Visual Basic(VBA)
-
エクセル:マクロ「Application.CutCopyMode = False」って?
Excel(エクセル)
-
-
4
vbaのエラー対応(実行時エラー7:メモリが不足しています)
Visual Basic(VBA)
-
5
Excel VBA 処理後データが重たくなる&処理スピードが遅いのを解決したい
Visual Basic(VBA)
-
6
VBAで保存しないで閉じると空のBookが残る
Excel(エクセル)
-
7
エクセルのラベルの値(文字列)を垂直方向で中央揃えにするには?
Excel(エクセル)
-
8
エクセルVBA 配列からセルに「関数式」を一気代入したい
Visual Basic(VBA)
-
9
【Excel VBA】 WorksheetやRangeオブジェクトとして宣言した変数の開放は必要でしょうか?
その他(Microsoft Office)
-
10
ReDim PreserveよりもReDimが遅い
Visual Basic(VBA)
-
11
EXCEL VBA マクロ 実行する度に処理速度がどんどん遅くなる原因が知りたい
Excel(エクセル)
-
12
DoEventsが必要な理由について
Visual Basic(VBA)
-
13
ユーザーフォームを表示中にシートの操作をさせるには
Excel(エクセル)
-
14
ユーザーフォームをホイールでスクロールする方法(Excel2000VBA)
Excel(エクセル)
-
15
動的配列が存在(要素が有る)か否かを判定できますか?
Visual Basic(VBA)
-
16
エクセルVBA テキストボックスに3桁ごとにコンマ
Visual Basic(VBA)
-
17
エクセル・VBA CheckBoxのオブジェクト名に変数を使うことは可能でしょうか?
Excel(エクセル)
-
18
VBAのコマンドボタンの文字列の改行方法は?
Visual Basic(VBA)
-
19
配列の値を置換するにはどうすればいいでしょう?
Excel(エクセル)
-
20
ExcelのVBA。public変数の値が消える
Visual Basic(VBA)
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語 配列の長さの上限
-
先頭アドレスとは何ですか?
-
リスト構造について
-
【速いブラインドタッチ】手を...
-
テキストファイルから文字列を...
-
複数の選択範囲の行番号を個別...
-
メモリの初期値
-
VBで構造体の配列を関数に渡す...
-
Redimした動的配列はEraseする...
-
VBAでクラス設定
-
配列を使わずに、変数名を動的...
-
配列を含む構造体の初期値について
-
配列をEraseしてもメモリが開放...
-
defineを使った配列
-
C言語でcharの足し算
-
配列で格納したものをmsgboxで...
-
ポインタの配列のコンマについて
-
char型の配列 char buff[20] = ...
-
電子書籍を見るためにはどうし...
-
【C言語】配列の中に配列を入れ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語 配列の長さの上限
-
配列を使わずに、変数名を動的...
-
C# Listを使わずに2次元配列の...
-
【速いブラインドタッチ】手を...
-
配列をEraseしてもメモリが開放...
-
テキストファイルから文字列を...
-
先頭アドレスとは何ですか?
-
配列で格納したものをmsgboxで...
-
複数の選択範囲の行番号を個別...
-
C# 配列の変数宣言について。
-
C++ vectorに配列をプッシュしたい
-
配列を含む構造体の初期値について
-
VBで構造体の配列を関数に渡す...
-
C言語で特定列だけを抽出して配...
-
キーボードのキー配列について
-
ExcelVBAで質問です。離れた二...
-
2次元配列を戻り値とする関数?
-
unsigned char配列への入力の仕方
-
【C言語】配列の中に配列を入れ...
-
Redimした動的配列はEraseする...
おすすめ情報