10

In one of my VB6 forms, I create several other Form objects and store them in member variables.

Private m_frm1 as MyForm
Private m_frm2 as MyForm

// Later...
Set m_frm1 = New MyForm
Set m_frm2 = New MyForm

I notice that I'm leaking memory whenever this (parent) form is created and destroyed. Is it necessary for me to assign these member variables to Nothing in Form_Unload()?

In general, when is that required?

SOLVED: This particular memory leak was fixed when I did an Unload on the forms in question, not when I set the form to Nothing. I managed to remove a few other memory leaks by explicitly setting some instances of Class Modules to Nothing, as well.

4

8 に答える 8

9

実際、VB6は C++ と同じようにRAIINothingを実装しています。これは、ローカルに宣言された参照がブロックの最後に自動的に設定されることを意味します。同様に、実行後にメンバー クラス変数を自動的にリセットする必要がありClass_Terminateます。ただし、これが確実に行われていないという報告がいくつかあります。厳密なテストは覚えていませんが、メンバー変数を手動でリセットすることが常にベスト プラクティスでした。

于 2008-08-27T15:27:05.903 に答える
8

@Matt Dillard - これらを何も設定しないでメモリリークを修正しましたか?

VB6には正式なガベージコレクタがなく、@Konrad Rudolphが言ったことに沿っています。

実際にフォームでアンロードを呼び出すことは、メインフォームがクリーンアップされ、各サブフォームがアクションをクリーンアップすることを保証する最良の方法のようです.

空白のプロジェクトと 2 つの空白のフォームでこれをテストしました。

Private Sub Form_Load()
  Dim frm As Form2
  Set frm = New Form2
  frm.Show
  Set frm = Nothing
End Sub

実行後、両方のフォームが表示されたままになります。frm を何も設定しないとうまくいきませんでした...何もありません。

frm を何も設定しないと、このフォームに対して開かれている唯一のハンドルは、参照を介したものになります。

Unload Forms(1)

問題を正しく認識していますか?

  • ジョシュ
于 2008-08-27T17:23:30.600 に答える
5

VBのオブジェクトには参照カウントがあります。これは、オブジェクトが、そのオブジェクトへの参照を保持している他のオブジェクト変数の数をカウントし続けることを意味します。オブジェクトへの参照がない場合、オブジェクトは(最終的に)ガベージコレクションされます。このプロセスはCOM仕様の一部です。

通常、ローカルでインスタンス化されたオブジェクトがスコープ外になると(つまり、サブを出ると)、その参照カウントが1つ減ります。つまり、オブジェクトを参照している変数が破棄されます。したがって、ほとんどの場合、Subを終了するときにオブジェクトをNothingに明示的に設定する必要はありません。

他のすべてのインスタンスでは、参照カウントを(1つ)減らすために、オブジェクト変数を明示的にNothingに設定する必要があります。オブジェクト変数をNothingに設定しても、必ずしもオブジェクトが破棄されるわけではありません。すべての参照をNothingに設定する必要があります。この問題は、再帰的なデータ構造で特に深刻になる可能性があります。

もう1つの落とし穴は、オブジェクト変数宣言でNewキーワードを使用する場合です。オブジェクトは、Newキーワードが使用された時点ではなく、最初の使用時にのみ作成されます。宣言でNewキーワードを使用すると、参照カウントがゼロになるたびに、最初の使用時にオブジェクトが再作成されます。したがって、オブジェクトをNothingに設定すると、オブジェクトが破壊される可能性がありますが、再度参照されると、オブジェクトは自動的に再作成されます。理想的には、Newキーワードを使用して宣言するのではなく、この復活動作を持たないNew演算子を使用して宣言する必要があります。

于 2008-09-29T11:31:28.077 に答える
4

@マーティン

VB6 には、C#.NET の Using() ステートメントのように機能する "With/End With" ステートメントがありました。そしてもちろん、グローバルなものが少なければ少ないほど、あなたにとっては良いことです。

With/End With は Using ステートメントのようには機能せず、ステートメントの最後で "Dispose" しません。

With/End With は、VB.Net と同じように VB 6 で機能します。基本的には、オブジェクトのプロパティ/メソッド呼び出しをショートカットする方法です。例えば

With aCustomer
  .FirstName = "John"
  .LastName = "Smith"
End With
于 2008-08-27T15:11:41.993 に答える
2

厳密に言えば決してそうではありませんが、ガベージ コレクターに物事をクリーンアップするための強力なヒントを与えます。

原則として、作成したオブジェクトを使い終わるたびに実行してください

于 2008-08-27T15:05:45.830 に答える
2

VB6 参照を Nothing に設定すると、VB がそのオブジェクトに対して持っている参照カウントが減少します。カウントがゼロの場合にのみ、オブジェクトは破棄されます。

Nothing に設定したからといって、.NET のように「ガベージ コレクション」されるとは思わないでください。

VB6 は参照カウンターを使用します。

C/C++ コードなどを参照するインスタンス化されたオブジェクトを "Nothing" に設定することをお勧めします。久しぶりにVB6に触れましたが、ファイルやリソースを何も設定していなかった記憶があります。

どちらの場合でも問題はありませんが (既に Nothing の場合)、オブジェクトが破棄されるという意味ではありません。

VB6 には、C#.NET の Using() ステートメントのように機能する "With/End With" ステートメントがありました。そしてもちろん、グローバルなものが少なければ少ないほど、あなたにとっては良いことです。

どちらの場合でも、大きなオブジェクトを作成すると、参照を維持して再利用するよりもコストがかかる場合があることに注意してください。

于 2008-08-27T15:07:40.707 に答える
2

私はしばらく前にこれに似た問題を抱えていました。アプリの終了も防げると思いますが、こちらに当てはまるかもしれません。

私は古いコードを引き上げました。それは次のようになります。

Dim y As Long
For y = 0 To Forms.Count -1
    Unload Forms(x)
Next

m_frm1 をアンロードする方が安全かもしれません。何も設定しないでください。

于 2008-08-27T15:07:44.703 に答える