在下面的代码中,  
 
               private  void  button1_Click(object  sender,  EventArgs  e)  
               {  
                       MyForm  myForm  =  new  MyForm();  
                       myForm.Show();  
               }  
         
       一般来说,myForm这个对象在button1_Click方法结束后,生命周期便结束,将会被GC清除。但是实际上myForm对应的窗口如果不按右上角“关闭按钮”是不会被GC清除的。为什么GC会对myForm“另眼相看”呢?  
 
       对C#和GC理解有限,请各位大侠出手释惑!

解决方案 »

  1.   

    dou luan tao le,mei fa zi hui da le ,wen zi quan shi luan ma le ,csdn dou tan huan le
      

  2.   

    如果 楼主 学习过c/c++
    这个 是很 容易理解的 事情  虽然C#里面不存在真实的指针 但是 new 一个对象的时候 同样可以看作是对这个对象的动态指针定义.
    要知道 局部的 动态指针 是不会在函数结束后 自动消亡的. 
    这样 就只有等待 GC来回收了.我的理解是这样 大家共同探讨  
    *****************************************************************************
    有空 来坐坐.我的Bloghttp://blog.csdn.net/hertcloud/
      

  3.   

    hehe,大致理解同楼上,但没楼上表述的清楚有C++的基础很多课程容易学些
      

  4.   

    不太同意楼上关于类似c++的指针的比方
    winform 背后应该关联于真实的windows窗口,可以从from.Handler属性看出
    他不能被垃圾回收类似于sqlconnection 它关联于一个非托管的资源。或者说它不是纯粹的.net类。
      

  5.   

    myForm.Show();  //关键应该是这句吧
    虽然不太了解,但如果不show 退出方法后是会被回收的
    show出之后是不是就进入了 另外一个相对的进程啊?这个进程消亡之前是不会被回收的(界面?)
      

  6.   

    Show的时候,对象实体又没消亡, 点关闭的时候执行了 dispose方法的呀
      

  7.   

    Reflector很快就找到了:当对Form调用Show方法时,会设置其Visible属性为true,而在Visible属性的set方法中,调用SetVisibleCore方法,这个方法被Form重写,代码如下:[EditorBrowsable(EditorBrowsableState.Advanced)]
    protected override void SetVisibleCore(bool value)
    {
        if ((this.GetVisibleCore() != value) || (this.dialogResult != DialogResult.OK))
        {//这里应该是判断Visible是否发生改变或者dialogResult是不是OK
            if ((this.GetVisibleCore() == value) && (!value || this.CalledMakeVisible))
            {//这里进一步的确认Visible没有发生改变(注意上面的if,其实这个分支的第一个判断就是判断dialogResult是不是OK,如果dislogResault不是OK,那么这里的this.GetVisibleCore() == value与上面的条件互斥),并且visible被设为false或者自己的CalledMakeVisible属性为true。
                base.SetVisibleCore(value);
            }
            else
            {//换言之,这里是this.GetVisibleCore()发生了改变的分支
                if (value)//如果Visible被设置为true
                {
                    this.CalledMakeVisible = true;
                    if (this.CalledCreateControl)
                    {
                        if (this.CalledOnLoad)
                        {
                            if (!Application.OpenFormsInternal.Contains(this))
                            {
                                Application.OpenFormsInternalAdd(this);//关键在这里,真相大白
                            }
                        }
                        else
                        {
                            this.CalledOnLoad = true;
                            this.OnLoad(EventArgs.Empty);
                            if (this.dialogResult != DialogResult.None)
                            {
                                value = false;
                            }
                        }
                    }
                }
                else
                {
                    this.ResetSecurityTip(true);
                }
                if (!this.IsMdiChild)
                {
                    base.SetVisibleCore(value);
                    if (this.formState[FormStateSWCalled] == 0)
                    {
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, base.Handle), 0x18, value ? 1 : 0, 0);
                    }
                }
                else
                {
                    if (base.IsHandleCreated)
                    {
                        this.DestroyHandle();
                    }
                    if (!value)
                    {
                        this.InvalidateMergedMenu();
                        base.SetState(2, false);
                    }
                    else
                    {
                        base.SetState(2, true);
                        this.MdiParentInternal.MdiClient.PerformLayout();
                        if ((this.ParentInternal != null) && this.ParentInternal.Visible)
                        {
                            base.SuspendLayout();
                            try
                            {
                                SafeNativeMethods.ShowWindow(new HandleRef(this, base.Handle), 5);
                                base.CreateControl();
                                if (this.WindowState == FormWindowState.Maximized)
                                {
                                    this.MdiParentInternal.UpdateWindowIcon(true);
                                }
                            }
                            finally
                            {
                                base.ResumeLayout();
                            }
                        }
                    }
                    this.OnVisibleChanged(EventArgs.Empty);
                }
                if ((value && !this.IsMdiChild) && ((this.WindowState == FormWindowState.Maximized) || this.TopMost))
                {
                    if (base.ActiveControl == null)
                    {
                        base.SelectNextControlInternal(null, true, true, true, false);
                    }
                    base.FocusActiveControlInternal();
                }
            }
        }
    }
      

  8.   

    为了清晰,我们摘出关键代码重新审定逻辑.if ( this.dialogResult != DialogResult.OK )
    {
        if ( !value || this.CalledMakeVisible )
        {
            base.SetVisibleCore(value);
        }
        else if ( this.GetVisibleCore() != value )
        {
            if (value)
            {
                this.CalledMakeVisible = true;
                if (this.CalledCreateControl && this.CalledOnLoad)
                {
                    if (!Application.OpenFormsInternal.Contains(this))
                    {
                        Application.OpenFormsInternalAdd(this);//关键在这里,真相大白
                    }
                }
            }
       }
    }
      

  9.   

    if ( this.dialogResult != DialogResult.OK && (!value || this.CalledMakeVisible) )
    {
        base.SetVisibleCore(value);
    }
    else if ( this.GetVisibleCore() != value )
    {
        if (value)
        {
            this.CalledMakeVisible = true;
            if (this.CalledCreateControl && this.CalledOnLoad)
            {
                if (!Application.OpenFormsInternal.Contains(this))
                {
                    Application.OpenFormsInternalAdd(this);//关键在这里,真相大白
                }
            }
        }
    }嗯……刚提取错了……
      

  10.   

    To hertcloud :    我理解你的意思,一般都是这样理解的,函数退出以后,堆栈(stack)会清空,myForm生命周期结束,这样myForm所指向的堆(heap)空间便失去指向他指针,垃圾收集器(GC)会在适当时候启动把myForm占用的堆(heap)空间释放。   但是现在的问题是,如果不手动把myForm对应的窗口关闭,我感觉GC应该永远不会清除myForm,这说明myForm这样对象比较特殊,不象一般的对象(比如装箱后int32),为什么会这样呢?就是因为myForm含有非托管资源吗?GC如何判断一个对象含有非托管资源的?----------------------------------------------------------
    hertcloud(·£孙子兵法£·) ( 四星(高级)) 信誉:100  2007-6-1 8:56:32  得分:0
    ?  如果 楼主 学习过c/c++
    这个 是很 容易理解的 事情 虽然C#里面不存在真实的指针 但是 new 一个对象的时候 同样可以看作是对这个对象的动态指针定义.
    要知道 局部的 动态指针 是不会在函数结束后 自动消亡的.
    这样 就只有等待 GC来回收了.我的理解是这样 大家共同探讨
      

  11.   

    还是不同意楼上,.net把窗体为我们作了封装,不是楼上想的那么简单
    不信可以做个试验
    form.Dispose( .. )
    {
     加一句
      MessageBox.Show("my clear");
    }
    from1 f1 = new f1();
    //这里不加show
    看看什么情况???
      

  12.   

    Ivony兄,你动作好快!这样说来就是因为
    Application.OpenFormsInternalAdd(this);
    这句话使得myForm的指针并没有丢失,因此GC不会对myForm指向那块堆空间“下毒手”,是不是这样的?另:你贴的这些.net自己的代码是怎么看到的?
      

  13.   

    目前在win32没有退出舞台之前,最好学习一下c 的win32编程,你就会清楚一个windows窗体的生死,这里所谓from只不过是一层包装。具体这个包装如何做,详细地可能需要微软才能回答。
      

  14.   

    hdt兄你说的和Ivony应该是一致的,估计不加Show方法的话,应该是类似一个普通的对象,不过也不敢百分之百保证,因为不知道new f1()的时候到底.net替我们做了些什么。
      

  15.   

    从我们这种.net下的使用者角度来看,也只能回答,form不是一个完全的托管资源,不完全受gc控制。
    具体的操作,不仅在il层次上,还有更底层因素在里面
      

  16.   

    MyForm  myForm  =  new  MyForm();  
    myForm.Show();  ------------------------------------
    首先退出方法体后,确实被释放了,但释放的是指向对象的指针:myForm,而不是变量指向的内存.因为Form是引用类型的.因用类型的对象的释放并不是指指向它的指针的释放!
      

  17.   

    首先退出方法体后,确实被释放了,但释放的是指向对象的指针:myForm,而不是变量指向的内存.因为Form是引用类型的.因用类型的对象的释放并不是指指向它的指针的释放!
    =======================
    瞎说
    Dispose 没有被执行如何释放
      

  18.   

    hdt兄,说的对,我最近就在C+win32 sdk和C#+.NET一块学,感觉win32sdk中窗口的生死过程暴露的比较清楚,而C#+.net要复杂些,因为有GC机制搀和进来,而且还有.net替我们做的工作,比如myForm.Show()等这些
      

  19.   

    我觉得在做WinForm的时候,Win32和.NET要区别对待,毕竟他们两个的游戏规则是不同的……。.NET只是对Win32的东西进行了一个封装,那么,我们既要知道这个封装是怎么封的,也要知道封装在里面的东西是怎么运作的。
      

  20.   


    另:你贴的这些.net自己的代码是怎么看到的?Reflector
      

  21.   

    虽然不知道是怎么做的,但的确可以做到GC.KeepAlive 方法 
    引用指定对象,使其从当前例程开始到调用此方法的那一刻为止均不符合进行垃圾回收的条件。
      

  22.   

    瞎说
    Dispose 没有被执行如何释放
    -----------------------------------------
    hdt(倦怠) ( ) 信誉:120    Blog   加为好友 
    说话太过肯定了你看清了吗...
      

  23.   

    看来关于GC还是要结合含有非托管资源对象的特点深入学习一下,才能更好地预料代码的动作。==================================================================================
    引用自phommy(石头,竹子,诗) :
    虽然不知道是怎么做的,但的确可以做到GC.KeepAlive 方法
    引用指定对象,使其从当前例程开始到调用此方法的那一刻为止均不符合进行垃圾回收的条件。
      

  24.   

    用.Net就是为了快速开发...知道它是一个非托管资源就可以啦....^o^
      

  25.   

    觉得这个和是不是C++无关.在MFC中显示一个窗口的时候不也是这样的吗.
      

  26.   

    MyForm  myForm  =  new  MyForm();  
    myForm.Show();  ------------------------------------
    首先退出方法体后,确实被释放了,但释放的是指向对象的指针:myForm,而不是变量指向的内存.因为Form是引用类型的.因用类型的对象的释放并不是指指向它的指针的释放!
    ======
    myForm 只是相当于个别名,何来释放?
      

  27.   

    恩,不过如果不了解一下内部机制,窗口操作又比较频繁、复杂的话,可能一些coding的细节会影响代码的健壮性=====================================================
    引用自shinaterry(簡簡⿺單單..) ( 
    用.Net就是为了快速开发...知道它是一个非托管资源就可以啦....^o^
      

  28.   

    TO:hdt(倦怠) ( )我错了,不该知道的太少,不该在这里和大家研究问题,更不该在这里发表我的不成熟的意见.
    我向来以做出不让人理解的事而烦恼,也以自己的见识短小而自卑,请老师以后多多说教,多多说教.
      

  29.   

    看看这篇文章可能会对理解这个问题有帮助ms-help://MS.MSDNQTR.2003FEB.2052/cpguide/html/cpconimplementingdisposemethod.htm
      

  30.   

    平民
    我只是就事论事,可能说话有些冲,先到个歉
    这个问题我的理解也只是基于猜测而已。
    毕竟.net他对此作了完善的封装。里面具体执行了什么,水平不够只能猜了
      

  31.   

    长见识了,我认同Ivony(授人以鱼不如授人以渔,上海谋生) 的观点
      

  32.   

    这不是主线程啊,你的主线程是被Application.Run(...)启起来的啊.
    所有的窗体运行都在它的UI主线程的管理下运行的,你的一个窗体执行了SHOW,主线程会控制这个窗体的显示.和其它的操作..
      

  33.   

    可是Application.Run基本上只完成消息循环功能,关于对象的dispose它是不管的,
    而且这个方法是在主线程中的,是主界面的一个按钮的click事件===============================================================
    引用自(brucenan999(布鲁斯南))
    这不是主线程啊,你的主线程是被Application.Run(...)启起来的啊.
    所有的窗体运行都在它的UI主线程的管理下运行的,你的一个窗体执行了SHOW,主线程会控制这个窗体的显示.和其它的操作..
      

  34.   

    窗体SHOW之后,虽然你的CLICK函数结束了,但是窗体对象还存在啊,而且被管理着,它自己的生命周期并没有结束,直到你把它叉掉...
      

  35.   

    请问Ivony兄:你说的Reflector是在哪里down的?
      

  36.   

    恩,这种说法我同意,怎么被“管理”的——通过看Ivony贴的Code可以看出些蛛丝马迹============================================================
    引用自
    brucenan999(布鲁斯南) ( 四级(中级)) 信誉:99  2007-06-01 16:07:22  得分:0

    窗体SHOW之后,虽然你的CLICK函数结束了,但是窗体对象还存在啊,而且被管理着,它自己的生命周期并有结束,直到你把它叉掉...
      

  37.   

    请问Ivony兄:你说的Reflector是在哪里down的?我已经发到你邮箱了……
      

  38.   

    是因为Application.OpenForms还包含关于窗体的引用
      

  39.   

    <script type='text/javascript' language='javascript'>
    alert('123');
    </script>