事件注册与潜在隐患

[ 2005-07-31 14:17:16 | 作者: yuhen ]
字号: | |
首先看一段模拟代码
    class EnterpriseComponent
    {
        public event EventHandler OnEvent;

        ~EnterpriseComponent()
        {
            Console.WriteLine("EnterpriseComponent Destroy...");
        }

        public void DoEvent()
        {
            if (OnEvent != null)
                OnEvent(this, EventArgs.Empty);
        }
    }

    class Client
    {
        ~Client()
        {
            Console.WriteLine("Client Destroy...");
        }

        public void OnEvent(object sender, EventArgs e)
        {
            Console.WriteLine("Event...");
        }
    }

    class Program
    {
        static void Main(string[] args) 
        { 
            EnterpriseComponent eco = new EnterpriseComponent();
            Client client = new Client();

            // 注册事件
            eco.OnEvent += new EventHandler(client.OnEvent);

            // 执行事件
            eco.DoEvent();

            // 模拟Client超出作用范围,等待垃圾回收。
            client = null;

            // 执行垃圾回收
            Console.WriteLine("--GC Strat ---------------");
            GC.Collect();
            Console.WriteLine("--GC End------------------");
        } 
    }

输出:
Event...
--GC Strat ---------------
--GC End------------------

执行这段代码,我们可以看出,Client并没有被垃圾回收。
接下来,我们添加一行代码,再来一次。
        static void Main(string[] args) 
        { 
            EnterpriseComponent eco = new EnterpriseComponent();
            Client client = new Client();

            // 注册事件
            eco.OnEvent += new EventHandler(client.OnEvent);

            // 执行事件
            eco.DoEvent();

            eco.OnEvent -= new EventHandler(client.OnEvent); // <----- 添加的代码,取消事件注册!!!

            // 模拟Client超出作用范围,等待垃圾回收。
            client = null;

            // 执行垃圾回收
            Console.WriteLine("--GC Strat ---------------");
            GC.Collect();
            Console.WriteLine("--GC End------------------");
        } 

输出:
Event...
--GC Strat ---------------
Client Destroy...
--GC End------------------

可以看出,Client在取消事件注册后被GC回收。其原因就是如果没有取消事件注册,那么委托链表中的强引用就不会失效,因此GC也就无法回收。相关细节可以参考SDK中有关事件和委托的说明,在此不做详述。


注意:只要一个对象仍然登记有另一个对象的事件,该对象就不可能被执行垃圾回收。建议配合IDisposeable接口,在对象失效前取消事件注册,否则可能造成潜在的内存泄漏。
[最后修改由 yuhen, 于 2006-08-11 18:41:25]
评论Feed 评论Feed: http://www.rainsts.net/feed.asp?q=comment&id=83

这篇日志没有评论。

发表评论
表情图标
[smile] [confused] [cool] [cry]
[eek] [angry] [wink] [sweat]
[lol] [stun] [razz] [redface]
[rolleyes] [sad] [yes] [no]
[heart] [star] [music] [idea]
UBB代码
转换链接
表情图标
悄悄话
用户名:   密码:  
验证码 * 请输入验证码