.Net のガベージ コレクター

# 弱参照

.NET では、オブジェクトへの参照が残っていない場合、GC がオブジェクトを割り当てます。したがって、コードからオブジェクトにアクセスできる間 (オブジェクトへの強い参照がある場合)、GC はこのオブジェクトを割り当てません。大きなオブジェクトが多数ある場合、これは問題になる可能性があります。

弱い参照は、オブジェクトへのアクセスを許可しながら、GC がオブジェクトを収集できるようにする参照です。弱参照は、強参照が存在しない場合、オブジェクトが収集されるまでの不確定な時間だけ有効です。弱い参照を使用すると、アプリケーションは引き続きオブジェクトへの強い参照を取得できるため、オブジェクトが収集されなくなります。したがって、弱い参照は、初期化にコストがかかる大きなオブジェクトを保持するのに役立ちますが、アクティブに使用されていない場合はガベージ コレクションに使用できるはずです。

簡単な使い方:

WeakReference reference = new WeakReference(new object(), false);

GC.Collect();

object target = reference.Target;
if (target != null)
  DoSomething(target);

そのため、弱い参照を使用して、たとえばオブジェクトのキャッシュを維持できます。ただし、強い参照が再確立される前にガベージ コレクターがオブジェクトに到達するリスクが常にあることを覚えておくことが重要です。

弱い参照は、メモリ リークを回避するためにも便利です。典型的な使用例はイベントです。

ソース上のイベントへのハンドラがあるとします:

Source.Event += new EventHandler(Handler)

このコードは、イベント ハンドラーを登録し、イベント ソースからリスニング オブジェクトへの強力な参照を作成します。ソース オブジェクトの有効期間がリスナーよりも長く、イベントへの参照が他にないときにリスナーがもうイベントを必要としない場合、通常の .NET イベントを使用するとメモリ リークが発生します。ソース オブジェクトは、リスナー オブジェクトをメモリ内に保持します。ガベージコレクションする必要があります。

この場合、Weak Event Pattern を使用することをお勧めします。

次のようなもの:

public static class WeakEventManager
    {
    public static void SetHandler<S, TArgs>(
    Action<EventHandler<TArgs>> add,
    Action<EventHandler<TArgs>> remove,
    S subscriber,
    Action<S, TArgs> action)
    where TArgs : EventArgs
    where S : class
        {
            var subscrWeakRef = new WeakReference(subscriber);
            EventHandler<TArgs> handler = null;

            handler = (s, e) =>
            {
                var subscrStrongRef = subscrWeakRef.Target as S;
                if (subscrStrongRef != null)
                {
                    action(subscrStrongRef, e);
                }
                else
                {
                    remove(handler);
                    handler = null;
                }
            };

            add(handler);
        }
    }

このように使用されます:


EventSource s = new EventSource();
 Subscriber subscriber = new Subscriber();
 WeakEventManager.SetHandler<Subscriber, SomeEventArgs>(a => s.Event += a, r => s.Event -= r, subscriber, (s,e) => { s.HandleEvent(e); });

この場合、もちろんいくつかの制限があります - イベントは

public event EventHandler<SomeEventArgs> Event;

MSDN が示唆するように:

  • ファイナライズ後のオブジェクトの状態は予測できないため、長い弱参照は必要な場合にのみ使用してください。
  • 小さなオブジェクトへの弱参照の使用は避けてください。ポインタ自体が同じかそれ以上になる可能性があるためです。
  • メモリ管理の問題に対する自動的な解決策として弱い参照を使用することは避けてください。代わりに、アプリケーションのオブジェクトを処理するための効果的なキャッシュ ポリシーを開発してください。
  • # 大きなオブジェクト ヒープの圧縮

    デフォルトでは、ラージ オブジェクト ヒープは従来のオブジェクト ヒープとは異なり圧縮されません。これにより、メモリの断片化が発生し、さらに 08 が発生する可能性があります。

    .NET 4.5.1 以降では、ラージ オブジェクト ヒープを (ガベージ コレクションと共に) 明示的に圧縮するオプションがあります。

    GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
    GC.Collect();   
    
    

    明示的なガベージ コレクション要求 (CLR が実行を強制されないため、要求と呼ばれます) と同じように、注意して使用し、可能であればデフォルトで回避します。 の統計、そのパフォーマンスを低下させます。


    No