0

CacheState という名前のシングルトン クラスがあります。このクラスは多くのイベントを公開しています。CacheState には、これらすべてのイベントをループしてトリガーする System.Timers.Timer があります。

次に、asp.net アプリケーションで、Application_Start 中にこれらのイベントをサブスクライブします。この間に CacheState のタイマーも開始されます。

protected void Application_Start(object sender, EventArgs e)
        {           
                CacheState.Instance.ProductChangedEvent += (objSender, argsE) => ProductService.ReloadProductCache(false);
                CacheState.Instance.PageflexChangedEvent += (objSender, argsE) => ProductService.ResetPageflexCache(false);
                CacheState.Instance.DeliveryChangedEvent += (objSender, argsE) => PricingRuleService.ResetDeliveryMethodsCache(false);
                CacheState.Instance.UIItemChangedEvent += (objSender, argsE) => TemplateService.ResetUIItemsCache(false);
                CacheState.Instance.ProductAttributeChangedEvent += Instance_ProductAttributeChangedEvent;
                CacheState.Instance.Start();

        }

C# イベントがメモリ リークを引き起こす可能性があることを読みました。それで、私がこれを間違っているかどうか誰かに教えてもらえますか?

ありがとう。

4

3 に答える 3

5

シングルトン インスタンスは、そのイベントをサブスクライブしたすべてのオブジェクトへの参照を保持します。それらのオブジェクトがシングルトン インスタンスより長く存続せず、これらのイベントからサブスクライブ解除しない場合、それらはメモリ内に残ります。これは、メモリ リークが発生する唯一のケースです。明らかに、リスナーの前にイベント ソースが破棄された場合、参照はクリアされ、リスナーを適切に登録解除すると、参照も残りません。

この問題を解決するには、Weak Event PatternIDisposableを実装するか、シングルトン イベントをリッスンするすべてのオブジェクトに実装して、それらがコード内で適切に破棄されるようにします。

もちろん、これはシングルトン オブジェクトだけでなく、イベント ソースとして機能するオブジェクトにも当てはまります。ただし、シングルトン イベント ソースは、通常、アプリケーションが実行されている限り存続し、少なくとも他のオブジェクトと同じくらい存続するため、特に危険なケースです。

于 2013-06-06T10:53:37.847 に答える
0
    // generic delegate for genric events
public delegate void EventsHandler<in TArgs>(TArgs args) where TArgs : EventArgs;

// generic singleton
public abstract class EventsBase<TEvents> where TEvents : class, new()
{
    private static readonly object lockObject = new object();

    private static volatile TEvents instance;

    public static TEvents Instance
    {
        get
        {
            if (instance == null)
            {
                lock (lockObject)
                {
                    if (instance == null)
                    {
                        instance = new TEvents();
                    }
                }
            }
            return instance;
        }
    }
}

public class EventArgs<T> : EventArgs
{
    public T Item { get; set; }

    public EventArgs(T item)
    {
        Item = item;
    }
}

public class MyEvents : EventsBase<MyEvents>
{

    public event EventsHandler<EventArgs<IList<int>>> OnCheckedDataBase;
    public event EventsHandler<EventArgs<IList<int>>> OnProcessedData;

    public void CheckedDataBase(IList<int> handler)
    {
        if (OnCheckedDataBase != null)
        {
            OnCheckedDataBase(new EventArgs<IList<int>>(handler));
        }
    }
    public void ProcessedData(IList<int> handler)
    {
        if (OnProcessedData != null)
        {
            OnProcessedData(new EventArgs<IList<int>>(handler));
        }
    }

 }

MyEvents.Instance.OnCheckedDataBase += OnCheckedDataBase; //register

MyEvents.Instance.CheckedDataBase(this);  //fire
于 2015-01-05T17:10:39.127 に答える
0

コードを介してイベントに複数回割り当てると、C# でメモリ リークが発生する可能性があります。これは、複雑なコードで発生する可能性があり、多くの場合、初心者に発生します。これにより、イベントハンドラが複数回実行されます。

これを回避する適切な方法は、イベントをアタッチ (+=) する前にデタッチ ( -= ) することです。それを管理する method にカプセル化するのが最善でした。

これにより、イベント処理メソッドへのポインターのイベント スタックが 1 つのエントリで満たされることが保証されます (必要な場合)。

これは、メモリ リークについて私が知っていることの 1 つです。

もう一つは参考文献です。イベント ハンドラがグローバル オブジェクトまたはグローバル オブジェクトのリストにアクセスして値を挿入し、追跡しない場合、イベント ハンドラはグローバル変数をインスタンス化、使用、参照などにします。しかし、これは設計によって異なります。

誰かがもっと知っているなら、私はこれを感謝します。

于 2013-06-06T10:58:01.730 に答える