[英]Subscribing to events published by a Singleton Class
我有一個名為CacheState的Singleton類。 此類發布了許多事件。 CacheState具有一個System.Timers.Timer,該循環循環並觸發所有這些事件。
然后,在我的asp.net應用程序中,我在Application_Start期間訂閱了這些事件。 在此期間,CacheState中的Timer也將啟動:
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#事件會導致內存泄漏。 因此,有人可以告訴我是否做錯了嗎?
謝謝。
單例實例包含對已預訂其事件的所有對象的引用。 如果這些對象的生存時間不及單例實例的時間長, 並且沒有取消訂閱這些事件,則它們將保留在內存中。 這是遇到內存泄漏的唯一情況。 顯然,如果事件源在您的偵聽器之前被釋放,則引用將被清除,並且如果您正確注銷了偵聽器,則也將沒有引用。
為了解決這個問題,您可以在所有監聽單例事件的對象中實現弱事件模式或實現IDisposable
,例如IDisposable
, 並確保將它們正確地放置在您的代碼中!
當然,這不僅適用於單例對象,而且適用於充當事件源的任何對象。 但是,單例事件源是一個特別危險的情況,因為它通常在應用程序運行時就存在,因此至少與其他任何對象一樣存在。
如果您多次通過代碼分配給事件,則C#可能導致內存泄漏。 這可能會發生在復雜的代碼中,並且經常發生在初學者身上。 因此,您的事件處理程序將被執行多次。
避免這種情況的一種正確方法是,在附加事件(+ =)之前先分離事件(-=),最好是將其封裝到管理該方法的方法中。
這樣可以確保指向您的事件處理方法的指針的事件堆棧完全填充了一個條目(如果需要的話)。
這是我對內存泄漏了解的一件事。
另一件事是引用。 如果您的事件處理程序訪問全局對象或全局對象列表並插入值,並且您不跟蹤,則事件處理程序將導致全局變量被實例化,使用,引用等。 但這取決於設計。
如果有人知道更多,我將不勝感激。
// 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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.