static class Program { 
/// <summary> 
/// 应用程序的主入口点。 
/// </summary> 
[STAThread] 
static void Main() { 
B b = new B(new A()); 
Console.Read(); 
b = null;//运行此代码后b之前引用的对象被释放 
Thread.Sleep(3500 * 1000); 
} public class A { 
private event EventHandler m_testEvent; 
public event EventHandler TestEvent { 
add { 
this.m_testEvent += value; 

remove { 
this.m_testEvent -= value; 


} public class B { 
public B(A a) { 
this.m_a = a; 
this.m_a.TestEvent += delegate(Object sender,EventArgs e) { 
this.process(); 
}; 
this.m_a.TestEvent += new EventHandler(m_a_TestEvent); 
} private A m_a; void m_a_TestEvent(object sender,EventArgs e) { 
this.process(); 
} private void process() { 
for(int i = 0;i >= 0;i++) { 



} 代码有点长 :) 
简单的讲:A对象是B对象的成员变量,在B的构造函数中又注册了A对象的事件; 
这样似乎造成了A、B的循环引用,但垃圾回收还是将B对象回收了。 
不清楚为什么B对象会被回收,有兴趣的一起讨论讨论 :D

解决方案 »

  1.   

    b=null  只是理解把引用b对象的地址值在内存里面情况,b对象并不一定立即被GC回收。
      

  2.   

    A对象是B对象的成员变量,在B的构造函数中又注册了A对象的事件; 
    关B是否 释放有什么关系.
    比如说你是一家商店的会员,你开通了新品通知业务(就是有什么新品会及时通知你) 
    然后突然一天,商店被政府给查封关门了.(就象你在程序中把 b=null )你就奇怪了,他怎么关门了呢?
    是不是只要你还是人家的会员,只要你开通了服务人家就永远不能被查封呢.不相关的
    这么说不知道你明白不..
      

  3.   

    写错了b=null  只是理解把引用b对象的地址值在内存里面清空,b对象并不一定立即被GC回收。
      

  4.   

    to:jietuan
    我是通过内存工具查看发现b被回收的,那个工具在内部调用了GC.Collect()。to:birdlonger
    .net判断垃圾回收的策略就是检测对象是否被引用吧;在这个例子中,b对象注册了a对象的事件,所以b对象被a对象引用了。
    这样b对象就处于被引用状态,按道理是不会被回收的。但真实情况是b被回收了。
    详细的引用关系应该是: a 引用了 EventHandler委托,EventHandler委托 引用了 b,b 引用了 a。(EventHandler委托是a的事件类型)
    实际的运行情况是:a、b、EventHandler委托对象都被系统回收了。