垃圾回收之避免意外回收

当我们的对象被多个父对象(集合)包含时,我们一定要小心。某一个父对象被回收的话,子实例也将被回收,那些还包含着他的其他父对象的某个记录将是空的或被称为“被释放”。  


看以下两个例子,第一个是Windows Form,我写一个控件,他将多次被应用到其他窗口中,所以用全局变量保存他。

全局类
public class EditContext
{
    Control loginCtl;
    
static EditContext()
    {
        current 
= new EditContext();
    }
    
static EditContext current;
    
/// <summary>
    
/// 当前对象
    
/// </summary>
    public static EditContext Current
    {
        
get{return current;}
    }

    
public EditContext()
    {   
        loginCtl 
= new LoginControl();
    }
    
public Control GetLoginControl()
    {            
        
return loginCtl;
    }
}

其中的LoginControl是一个用户控件,我将他加入到其他表单里去

Type type = typeof(ParentForm);
object obj = Activator.CreateInstance(type);
IShowLogin show 
= obj as IShowLogin;
if (show != null)
    show.Show(EditContext.Current.GetLoginControl());

表单实现IShowLogin方法

#region IShowLogin 成员

public void Show(Control aControl)
{
    
this.panel1.Controls.Add(aControl);
    
this.Show();//ShowDialog的话不会引起错误回收
}

#endregion
这里用反射来调用,当然你也可以直接构建ParentForm实例,效果是一样的点击ParentForm的关闭按键,他就会被回收器回收,此时作为ParentForm的子控件EditContext.loginCtl也会被回收,当第二次点击时,编译器会告诉你“无法访问已释放的对象。对象名:“LoginControl”。”。解决的办法是,在ParentForm的Closing事件里,清空对pannel1.Controls,以去掉对EditContext.loginCtl的引用。这样ParentForm被回收,EditContext.loginCtl才不会被错误回收。


再来看一个web项目下的代码,他很有趣,或说很麻烦,因为你要找到他有点困难。起码我无法跟你说如何能简单的模拟出来。


同样的,有一个访问太过频繁,我把记录存放在Application里了。而不是每个请求都需要全部数据,于是我设计了这个类

BroadcastContext
public class BroadcastContext
    {
        
public static BroadcastContext Current
        {
            
get
            {
                BroadcastContext obj 
= HttpContext.Current.Application["BroadcastContext_Current"as BroadcastContext;
                
if (obj == null)
                {
                    obj 
= new BroadcastContext();
                    HttpContext.Current.Application[
"BroadcastContext_Current"= obj;
                }
                
return obj;
            }
        }

        List
<MyObject> objs;
        
public BroadcastContext()
        {
            objs 
= new List<MyObject>();
        }

        
public void Add(MyObject obj)
        {
            if(obj!=null)
               objs.Add(obj);
        }
        
public List<MyObject> GetMyBroadcast(int pLastIndex)
        {
            List
<MyObject> retObjs = new List<MyObject>();
            
foreach (MyObject one in objs)
            {
                
if (one.Index > pLastIndex)//这里one可能是null(被回收了);
                    retObjs.Add(one);
            }
            
return retObjs;
        }        
    }

 


我们自己开发测试时很难发现上面的代码有问题。但多人同时访问你服务器时,GetMyBroadcast方法就会有麻烦。解决的方法是改变GetMyBroadcast方法,不使用List<MyObject> retObjs,改为返回其他类型。

posted @ 2009-12-16 17:27  生命体验之kevin-Y  阅读(347)  评论(0编辑  收藏  举报