2

そんなことありますか?

私はC++newコマンドのようなもの、つまりメモリの明示的な解放を必要とする(またはメモリリークのリスクがある)メモリの割り当てについて話しています。

フォーム/コントロール/その他のオブジェクトをに設定することで以前にいくつかのGDIリークの問題を解決しなければNothingならなかったことを覚えていますが、今は何を、なぜか思い出せないので、私は尋ねます...

VB6で開発するときに、メモリ管理について心配する必要がありますか?

4

3 に答える 3

8

VB6 のメモリ管理に関しては、いくつかの懸念事項があります。

1 つ目は、子クラスが親を指す、またはその逆の循環参照です。Nothing への参照を明示的に設定しないと、これはフォームだけでなく、特にターゲット オブジェクトのエディターであるダイアログにも当てはまります。繰り返しますが、すべてが何も設定されていないことを確認すると、問題が解決します。

基本原則は次のとおりです。1) オブジェクトが指すものが「生きている」場合、ガベージ コレクションは行われません。したがって、循環参照の親オブジェクトへの参照を設定すると、子は生きているため、親はガベージ コレクションを取得しません。親がまだ生きているため、子はガベージ コレクションを取得しません。

フォームも同様。オブジェクトを編集するダイアログのターゲット プロパティを何も設定しない場合、ターゲット オブジェクトが生きている限り、最後の一連のイベントは発生しません。

これを行うことの最も一般的な副作用は、アプリケーションが適切にシャットダウンされず、アプリケーションの使用時間が長くなるほどメモリ フットプリントが大きくなることです。

GDI リークに関しては、ハンドルやポインターを使用する外部 DLL を使用するたびに発生します。これらの関数については、C++ と同じ領域に身を置くことになります。そのため、使用している特定の API または DLL のすべての規則に従っていることを確認する必要があります。これには、使用後に作成したものを明示的に破棄することがよくあります。

循環参照の問題に対する洗練された解決策があります。子が親を直接参照する代わりに、プロキシを使用します。

まず、親オブジェクトのプロキシ クラスを作成します。

Option Explicit Public Event GetRef(ByRef RHS As MyObject)

Public Function GetMyObject() As MyObject
    Dim Ref As MyObject
    RaiseEvent GetRef(Ref)
    Set GetMyObject = Ref
End Function

次に、親でプライベート変数を定義します

Private WithEvents MyProxy As MyObjectProxy

Private Sub Class_Initialize()
    Set MyProxy = New MyObjectProxy
End Sub

次に、Proxy という読み取り専用プロパティを設定し、GetRef イベントを実装します。

Public Property Get Proxy() As MyObjectProxy
    Set Proxy = MyProxy
End Property

Private Sub MyProxy_GetRef(RHS As MyObject)
    Set RHS = Me
End Sub

参照が必要な子またはその他のコードは次のとおりです。

Private ParentProxy As MyObjectProxy

Public Property Get Parent() As MyObject
    If ParentProxy Is Nothing Then
        Set Parent = Nothing
    Else
        Set Parent = ParentProxy.GetRef
    End If
End Property

Public Property Set Parent(RHS As MyObject)
    If RHS Is Me Then
        Set MyObjectProxy = Nothing
    ElseIf Target Is Nothing Then
        Set MyObjectProxy = Nothing
    Else
        Set MyObjectProxy = RHS.Proxy
    End If
End Property

イベント メカニズムは、どちらのオブジェクトでも参照を設定したり、COM 参照カウントをインクリメントしたりしないため、多くの VB6 プログラマの悩みの種である循環参照の問題を回避できます。

注: 私が入手したソースではプロキシと呼ばれていましたが、Anthony のコメントのおかげで、メディエーター パターンの定義にも適合することがわかりました。特定の VB6 Centric 機能を使用します。Mediator パターンの精神に完全に沿っていない Event API です。

また、.NET フレームワークには VB6 のイベント API と同等のものがありますが、実装は異なります (デリゲートなど)。

于 2008-11-05T13:35:42.493 に答える
3

メモリ管理について心配する必要はないと言いたいのですが、それは完全に真実ではありません。VB6コードが実行されている実行環境にある程度依存します。COM+で実行されているVB6クラスは、終了時にオブジェクト参照をNothingに明示的に設定しないと、メモリリークが発生することは確かです。

環境問題はさておき、VB6タイプのシステム内で割り当てるメモリは、通常、クリーンアップされます。Newキーワードで割り当てるものについて話しています。しかし、rpetrichや他の人たちによって指摘された重要な例外があります:-

VBが割り当てられたオブジェクトの存続期間を管理するために使用する参照カウントメカニズムのため、循環参照がある場合はメモリリークが発生する可能性があります。たとえば、A-> B->C->Aです。そのようなシナリオがある場合は、おそらく自分でそれを見つけて、参照をNothingに明示的に設定することによってそれを修正する必要があります。私は、この種の問題を特定するのに大いに役立つツールを知りません。

他の言語で書かれたライブラリを使用していると、さらに問題が発生します。内部でメモリを割り当てるC++で記述されたCOMオブジェクトを新規作成し、そのメモリを解放するために特定のメソッド(Closeなど)を呼び出す必要があることに気付く場合があります。たぶん、そのようなCOMオブジェクトはひどく書かれているでしょうが、それらはたくさん存在します。

したがって、おそらく次の場合を除いて、従うべきルールはありません。

  1. 使用するライブラリの動作について可能な限り知るようにしてください。
  2. パフォーマンスモニターでメモリトレースを監視しながら常にコードを実行して、メモリ使用量が無制限に増加していないことを確認してください。
  3. 循環参照に注意してください;-)
于 2008-11-05T08:26:55.207 に答える
3

はい、さまざまなフォームで同様の問題が発生したため、アンロードごとに明示的に何も設定しませんでした。

しかし、ほとんどがサードパーティのコントロールにある問題は、すべてのCOM参照が正しくクリアされていない場合があるようです。

こちらをご覧ください。

于 2008-11-05T08:38:47.633 に答える