抽象化の失敗は、実際にはガベージコレクションが非決定的であるという事実ではなく、オブジェクトが参照を保持しているものに「興味がある」という考えであり、保持していないものには興味がない参照。理由を確認するために、特定のコントロールが描画される頻度のカウンターを維持するオブジェクトのシナリオを考えます。作成時に、コントロールの「ペイント」イベントをサブスクライブし、処分時にサブスクライブ解除します。クリックイベントは単にフィールドをインクリメントし、メソッドgetTotalClicks()
はそのフィールドの値を返します。
カウンターオブジェクトが作成されると、それが監視するコントロール内にそれ自体への参照が格納されるようにする必要があります。コントロールは本当にカウンターオブジェクトを気にせず、カウンターオブジェクトとその参照が存在しなくなっても同じように満足しますが、参照が存在する限り、毎回そのオブジェクトのイベントハンドラーを呼び出します。それは自分自身をペイントします。このアクションはコントロールにはまったく役に立たないものですがgetTotalClicks()
、オブジェクトを呼び出す誰にとっても役に立ちます。
たとえば、メソッドが新しい「paint-counter」オブジェクトを作成し、コントロールに対して何らかのアクションを実行し、コントロールが再描画された回数を観察してから、paint-counterオブジェクトを破棄した場合、オブジェクトはイベントにサブスクライブされたままになりますただし、オブジェクトとそのオブジェクトへのすべての参照が単純に消滅しても、だれも気にしません。ただし、コントロール自体が有効になるまで、オブジェクトはコレクションの対象にはなりません。メソッドがコントロールの有効期間内に何千回も呼び出されるものである場合(もっともらしいシナリオ)、メモリオーバーフローを引き起こす可能性がありますが、N呼び出しのコストはO(N ^ 2)またはO (N ^ 3)サブスクリプション処理が非常に効率的で、ほとんどの操作が実際にはペイントを含まない場合を除きます。
この特定のシナリオは、コントロールに強いオブジェクトではなくカウンターオブジェクトへの弱い参照を維持させることで処理できます。弱いサブスクリプションモデルは役立ちますが、一般的なケースでは機能しません。単一のコントロールから単一の種類のイベントを監視するオブジェクトが必要な代わりに、複数のコントロールを監視するイベントロガーオブジェクトが必要で、システムのイベント処理メカニズムが各コントロールに参照が必要であると想定します。別のイベントロガーオブジェクトに。その場合、コントロールをイベントロガーにリンクするオブジェクトは、両方が存在する限り、存続している必要があります。監視されているコントロールとイベントロガーは引き続き有用です。コントロールもイベントロガーもリンクイベントへの強い参照を保持していない場合、それがまだ「有用」であるにもかかわらず、イベントは存在しなくなります。どちらかが強いイベントを保持している場合、リンクしているオブジェクトの寿命は、他のオブジェクトが死んだとしても無駄に延長される可能性があります。
オブジェクトへの参照がユニバースのどこにも存在しない場合、そのオブジェクトは無用であると見なされ、存在から削除されます。ただし、オブジェクトへの参照が存在するという事実は、オブジェクトが「有用」であることを意味するものではありません。多くの場合、オブジェクトの実際の有用性は、GCの観点からは、それらとはまったく関係のない他のオブジェクトへの参照の存在に依存します。
オブジェクトに誰も興味がないときに決定論的に通知された場合、オブジェクトはその情報を使用して、その知識から恩恵を受けるだろう誰にでも通知されるようにすることができます。ただし、そのような通知がない場合、存在する参照のセットだけがわかっていて、それらの参照に関連付けられている意味的な意味がわからない場合、どのオブジェクトが「有用」と見なされるかを判断する一般的な方法はありません。したがって、GCがオブジェクトの破棄を即座に検出できたとしても、参照の存在または非存在が自動リソース管理に十分であると想定しているモデルは運命づけられません。