質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

2回答

50392閲覧

VBAメモリーリークについて

HayatoInoue

総合スコア13

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

3クリップ

投稿2015/12/21 04:19

VBAについて教えてください。
以下の様に、Loopの時間間隔を取得するプログラムを作成しています
lngTimer1 = GetTickCount
・・・・処理
Dim iTimer4 As Integer
lngTimer2 = GetTickCount
lngTimer3 = lngTimer2 - lngTimer1
iTimer4 = CInt(lngTimer3)
DoEvents
Worksheets("Sheet1").OLEObjects("LblTackt").Object.Caption = CStr(iTimer4)

この際、Worksheetsオブジェクトが実行されるたびにタスクマネージャのメモリが大きくなっていきます。
書き方でおかしいところはありますか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

VBAのメモリー管理は 参照カウンタ方式 です。仕組みはシンプルですが、漏れ無く開放 するにはそれなりの注意が必要です。

まずは、自分が以前に同様の問題の解決に役立ったページをご連携致します。実際にはかなり膨大な数のページを参照しましたが、とりあえず主だったものを3つだけ…

4.1.5 オブジェクト消滅の管理
Excelのプロセスが正常に終了しない理由(その1)
15.消えないExcelのプロセス

Excel VBA以外の話題も含まれていますが、原理は同じです。ちょっと長いのですが、辛抱して注意深くお読みください。

要点を簡単にまとめると、

  • メモリーリークが発生するのは参照カウンタが0になっていないために開放されないオブジェクトがあるから
  • 使用済みオブジェクトを確実に開放するには使用済みオブジェクトの参照カウンタを確実にデクリメントする
  • 「暗黙の参照」が発生しないように気をつける

このうち、一番面倒なのが、最後の『暗黙の参照を発生させない』という点です!

これは口で言うのは簡単なのですが実践するとなると結構面倒です。
自分はまだExcelのオブジェクトモデルの全容を把握出来ていないので、どこまでやれば必要十分確実なのかが分からないのですが、以下のようなコーディング方法はオブジェクトの開放漏れを発生させてしまうようです。

  • オブジェクトを省略してプロパティを指定する
  • 参照する個々のオブジェクトを逐一変数で受けずに使用する

2番目の『逐一変数で受ける』というのは分かりにくいですが、平たく言えば .(ピリオド)が2つ以上繋がるようなコーディング方法は暗黙の参照を引き起こし、オブジェクトの開放漏れに繋がる可能性があるということです。

ですから、(冗長な部分もあるかもしれませんが)参照カウンタを確実にデクリメントしてオブジェクトの開放漏れを防ぐには、以下のようなコーディング方法が必要ということになります。

(修正前) Worksheets("Sheet1").OLEObjects("LblTackt").Object.Caption = CStr(iTimer4) (修正後) Dim xlApp As Excel.Application Dim xlBook As Worksheet Dim objOle As Object Dim objTarget As Object Set xlApp = GetObject(, "Excel.Application") Set xlBook = xlApp.Worksheets("Sheet1") Set objOle = xlBook.OLEObjects("LblTackt") Set objTarget = objOle.Object objTarget.Caption = CStr(iTimer4) Set objTarget = Nothing Set objOle = Nothing Set xlBook = Notihng Set xlApp = Nothing

Excel VBA は気軽に手間なく実装出来るところが最大の魅力でもあるので、いわゆる手抜きをしたコーディング方法でも適宜暗黙の参照を適切に扱い実行可能にしてくれます。
扱うオブジェクトのサイズが小さかったり、ループ回数が少ない場合には、メモリーの枯渇が顕在化する前に作業が完了してExcelのブックを閉じてしまうので、細かいことを気にしなくても全く問題ありません。

しかし、

  • 巨大なオブジェクトを扱う
  • ループの回数が多い
  • 長時間プログラムを実行し続ける

などの場合には、参照カウンタのデクリメントを意識しながら使用の終わったオブジェクトを確実に開放しないと、メモリーリソースがすぐに枯渇して実行時エラーが発生してしまいます。

ですので、必ずしも全てを上記のような面倒なコーディング方法にしなくても良いと思いますが、

  • サイズの大きなオブジェクトを扱う場合
  • 繰り返し回数の多いループの中でオブジェクトを扱う場合

については、参照カウンタを明示的にデクリメントできるような実装方法を心がけてみてください。

以上、幾らかでもご参考になれば幸いです。

投稿2015/12/23 15:00

pi-chan

総合スコア5936

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ExcelVBAer

2015/12/23 15:58

勉強させて頂きました。
guest

0

とりあえず、以下で回避できませんか?

VBA

1Dim obj As OLEObject 2 3' 中略 4 5obj = Worksheets("Sheet1").OLEObjects("LblTackt") 6obj.Object.Caption = CStr(iTimer4) 7 8' 中略 9 10' obj が要らなくなったら 11Set obj = Nothing

これで解決したなら、「VBA OLEオブジェクト 解放」あたりで調べてみることをお勧めします。

投稿2015/12/21 05:42

編集2015/12/21 06:53
kozuchi

総合スコア1193

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ExcelVBAer

2015/12/21 06:15

最初と最後のコードは、 Set obj = ○○ と頭に[Set]が必要ですよね?
kozuchi

2015/12/21 06:45

おっしゃる通りです、ご指摘ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問