0

我有一个名为 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# 事件会导致内存泄漏。那么,谁能告诉我我做错了吗?

谢谢。

4

3 回答 3

5

单例实例包含对所有订阅其事件的对象的引用。如果这些对象的寿命不如单例实例,并且它们没有取消订阅这些事件,那么它们将保留在内存中。这是您遇到内存泄漏的唯一情况。显然,如果事件源在您的侦听器之前被释放,则引用将被清除,并且如果您正确取消注册侦听器,则也没有剩余引用。

为了解决这个问题,您可以实现弱事件模式IDisposable在所有监听单例事件的对象中实现,确保它们在您的代码中得到正确处理!

当然,这不仅适用于单例对象,也适用于任何充当事件源的对象。然而,单例事件源是一种特别危险的情况,因为它通常只要您的应用程序运行就存在,因此它的存在时间至少与任何其他对象一样长。

于 2013-06-06T10:53:37.847 回答
0

如果您通过代码多次分配给事件,C# 可能会导致内存泄漏。这可能发生在复杂的代码中,并且经常发生在初学者身上。因此,您的事件处理程序将多次执行。

避免这种情况的正确方法是在附加事件(-=)之前分离它(+=),最好是封装到一个方法中,它管理它。

这可确保指向您的事件处理方法的指针的事件堆栈恰好填充一个条目(如果需要)。

这是我所知道的关于内存泄漏的一件事。

还有一点是参考。如果您的事件处理程序访问全局对象或全局对象列表并插入值,而您没有跟踪,事件处理程序将导致全局变量被实例化、使用、引用等。但这取决于设计。

如果有人知道更多,我将不胜感激。

于 2013-06-06T10:58:01.730 回答
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 回答