VBAでの配列の開放について

このQ&Aのポイント
  • VBAを停止した時、配列のメモリは開放されているのか疑問です。エクセルファイルの処理で大きな配列を使用しているため、配列を繰り返し使用していますが、VBAを停止すると配列のメモリは開放されるのでしょうか。
  • エクセルの動作が重くなるため、配列のメモリが開放されていない可能性があります。VBA起動直後に配列のメモリを確認して開放する方法があれば教えてください。また、空の配列をチェックするコードを試しましたが、実行時エラーが発生しました。
  • 配列のメモリが開放されているかどうか疑問です。エクセルファイルの処理で大きな配列を使用しており、VBAを停止すると配列のメモリは開放されるのか不明です。エクセルの動作が重くなることがあり、配列のメモリが開放されていない可能性があるため、VBA起動直後に配列のメモリを確認して開放する方法を教えてください。
回答を見る
  • ベストアンサー

VBA 停止したら配列は開放されていますか?

 質問させていただきます。よろしくお願いいたします。 環境:Windows7 + エクセル2010 でございます。 少し気になりましたのでご質問させてください。  50MBほどのエクセルファイルでデータを加工するために、大きな配列を下記のように繰り返し使用する事がよくございます。 Do  ReDim varData(1000000, 10)   :   : ★  Erase varData Loop Until ~  Erase前(例えば★マークのところ)でエラーやブレークによる中断 →そのままVBAを「停止」(=四角いリセットボタンの事です) →デバッグしてからVBA再実行 を何度も繰り返しておりますが、「停止」させた時点でこの配列のメモリは開放されているのでしょうか?  といいますのが、何度もVBA実行→中断を繰り返しておりますとエクセルの動作が重くなってくる事があるので、上記の問題を疑ってエクセルを一度落として再起動することが時々あります。 (再起動すればメモリが残っていても開放されると思いますので。 しかしエクセルファイル自体が重いので、何が原因なのかは不明です。)  毎回きちんとEraseできればメモリは開放されると思うのですが。。。  あともしメモリ上に残っているのであればですが、VBA起動直後にそれを確認してEraseするようなコードがもしございましたらお教えいただけないでしょうか。 試しに Sub Test  If varData<> Empty Then Erase varData のような事をしてみましたが、 >実行時エラー13:型が一致しません のエラーが出てうまくいきませんでした。  もしお詳しい方がいらっしゃいましたら、どうぞよろしくお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • mitoneko
  • ベストアンサー率58% (469/798)
回答No.1

 一応、仕様としては、変数等で確保されたメモリーは、その実体への参照が無くなった時点で開放されることに、なっています。  おそらく、実際には、参照が無くなり、Excelのシステムがガベージコレクションを行う機会があった時に開放されるだと思われます。  さて、仕様ではこうなっていて、大概、このように動いているわけですが・・・デバッガーによるプログラムのブレークは、かなり特殊な状態です。  多分、メモリーがリークしていると思われます。  デバッグ中のプログラムを終了させた時点で、そのメモリーへのアクセスの手段は完全に失われていますので、これをイレースすることも当然出来ないですね。  多分、Excelの再起動が、もっとも現実的な処理だと思います。これなら、確実にメモリーは解放されます。普通の運用状態では起こりえない状態ですから、これをエラー処理の一環として組み込むというのは、ちょっと非現実的かなと思います。

linelan
質問者

お礼

 mitoneko様    どうもありがとうございます。    なるほどです。という事は今の認識でもそれほど間違っていなさそうですね。 分かりやすいご説明をいただけて勉強になりました。  この度はご親切にお教えいただき誠にありがとうございました。m(_ _)m

関連するQ&A

  • 配列をEraseしてもメモリが開放されていない?

    すみません。一度質問を載せた後で、補足で絵を載せようとしたのですができなかったので 再投稿させていただきます。(元の質問はけしました。) -------------------------------------- こんにちは、今作成しているエクセルの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

  • Redimした動的配列はEraseする必要があるのか

    Visual Basic6(SP5)で開発を行っているものです。 時々、「メモリが"Read"になることができませんでした」と言うエラーメッセージと共にVisual Basicのアプリケーションが終了する不具合が発生します。メモリ操作関連のエラーだろうと社内で指摘されました。 怪しいかと思われるのは、ある動的配列をRedimし、解放する必要が無いのでEraseしていない点です。 動的配列は、RedimしたらEraseしないとエラーの元になり得るのでしょうか? 時間のある方、ご回答願います。

  • メモリの解放について VB6 VBA

    VB6やVBAで動的配列をERASEしたのですが、タスクマネージャーで見ても使っているメモリを解放しているように見えません。 動的配列の内容をMsgBoxで表示させるたびにメモリがどんどん減っていきます。Eraseしても戻りません。 Redim ArryaDat(0)とかでも無理でした。 APIを使って(どんな方法)でも、メモリを解放したいのですが、可能でしょうか? Dim ArrayDat() as String Redim ArrayDat(100) ArrayDat(0) = "なんとか" ArrayDat(1) = "かんとか" ... ArrayDat(100) = "メモリを解放したい" for i = LBound(ArrayDat) to UBound(ArrayDat) MsgBox("どんどんメモリが消費されていく・・ [" & ArrayDat(i) & "]") next i Redim ArrayDat(0) Erase ArrayDat NsgBox("解放したつもり? 誰か教えて") あと、.NETではメモリ解放はどうなっているのでしょうか? まだ使いませんが、頭の片隅に入れておきたいです。

  • VB.netでの動的配列の扱い

    VB.net 2003で開発を行っています。 コード内で動的配列を多用しているんですが(要素数 2000000以上)、一度 ReDim でメモリ確保した配列は、いらなくなったと同時にErase したほうがいいんでしょうか。 配列を増やすほど実行速度が遅くなっていく気がします。 また、いっそのことVC++で書き直すと、実行速度は速くなる可能性はありますか。 VB.netのコードは、もちろん最適化のチェックをすべていれてあります。 どなたかご教授下さい。

  • VBAの動的配列について

    いつもお世話になっております。 エクセルVBAを学習中の者です。 動的配列についてお伺いします。 添付資料を見て頂きたいのですが、 シート名1~4に同一レイアウトの表があります。 これらの表をを2次元配列に格納し、その後、同一レイアウトのシートに一括転記したいと考えています。 転記の事を考えて、条件としては、 シート1から2行目以降のデータを配列『data』に格納、変数『dataCnt』が転記先の行番号と同じになるように考えています。 当初は、配列の定義を『Dim data(100,3) As Variant』と、多めに要素数を定義して、コードを記述していました。 正直、凄く気持ちが悪い感じでした・・・ 最近、動的配列を学習しまして、 シートごとにデータの行数を変数『lastRow』に格納して、配列を再定義して【データ数=要素数】とならないか? と思い、下記のようなコードを書いてみました。 が、『ReDim Preserve~』で実行エラーが発生してしまいます。 原因がなぜかわかりません! そもそも、動的配列はこのような使い方は出来ないのでしょうか? Sub テスト() Dim data() As Variant Dim x As Long Dim i As Long Dim ii As Long Dim lastRow As Long Dim dataCnt As Long dataCnt = 2 For x = 2 To 5 Worksheets(x).Activate lastRow = Cells(Rows.Count, 1).End(xlUp).Row If x = 2 Then ReDim data(2 To lastRow, 3) Else ReDim Preserve data(2 To dataCnt + lastRow - 1, 3) End If For i = 2 To lastRow For ii = 1 To 3 data(dataCnt, ii) = Cells(i, ii) Next ii dataCnt = dataCnt + 1 Next i Next x End Sub どなたかご指導をよろしくお願いいたします。

  • VBA でのシート内容を配列に保存した時の列の追加

    EXCEL VBAで開発をしています。 2つのEXCELファイルの各表(シート)にオーダーNo(ユニークキー)が あり、処理を書いています。 各表を二次元配列に保存して、行追加時に動的に配列を増やそうとしています。 その時、Redim Preserve を利用すると配列(行,列)と宣言しているので、第一引数にを追加しようとすると、”インデックスが有効範囲にありません”(-9)となりエラーとなります。 二次元配列で、第一引数は増やせない仕様ということは知っているのですが、このエラーを回避するためにどのようにするのが最善なのでしょうか? Excelシートのフィルタ昨日を利用したりして、他の方法で色々試したのですが、処理があまりにも重くて使えませんでした。 ですので、配列などのように内部処理にてデータ処理をして、 一気にシートへ出力という風に考えております。 何卒宜しくお願い致します。

  • VBAでオブジェクトの配列の配列の削除をすると動作異常になります

    VBA(Excel2000)でオブジェクト指向のお勉強をしておりますが、ミスか言語仕様か分からないトラブルがあり、困っております。 簡単な碁(碁盤を再現し、活き死に程度を判定する)のプログラムを作成していますが、クラス石の配列であるクラス群を作成し、更にクラス群の配列を石の黒・白別に標準モジュールで定義しています。一塊の石の群が死んでいると判定した時、その群を削除しようとするのですが、redim preserve 群の配列(添字-一番最後の)を実行すると、群の配列全体にアクセスできなくなってしまいます。redimする前に、Nothingを代入するとか、もとの群(石の配列)にNothingを代入してからredimするとかしてみましたが、事態は変わりませんでした。 仕様なのか、勘違いしているのか、クラスの使い方が分かっていないのか..アドバイスお願いします。

  • Excel VBA での動的配列の宣言の仕方

    Excel VBA で動的配列を宣言したところ,上手く行きません。何が悪いのでしょうか? Dim A() As Integer MsgBox LBound(A()) として実行すると,LBound(A())のインデックスが有効範囲にありませんというエラーが出ます いったい何が悪いのでしょうか?動的配列の定義に失敗しているものと思いますが,動的配列の宣言の仕方をお教えください。よろしくお願いします。

  • メモリ開放

    C#でのメモリの開放の仕方を教えてください。 二次元配列で1万、1万でやっているのですが、エラーが出てメモリが足りないと言われます。 開放をしたいのですが、ネットで探しても難しく書いてあって分かりません。おしえてください。

  • エラーになってないのにVBAが中断される

    エラーになってないし、止めてもいないのに、VBAが中断される エクセル2010なのですが、マクロを実行すると、一定の間隔でマクロが中断してしまいます。 中断箇所は ・End With ・Set WSH = Nothing ・If tmp Like "*文字*" Then などです。 「コードの実行が中断されました」と表示されます。 中断キーは押していません。 再起動すると治るのですが、どうしてこのような現象が発生するのでしょうか?

専門家に質問してみよう