none
关于Dispose方法使用的问题 RRS feed

  • 问题

  • 为了增加软件释放内存的功能,我查了msdn,使用Dispose方法

    由于是初学者,按msdn的代码复制到工程中,发现其中两个定义对象或变量的语句出错,不知道该引用哪个命名空间,请大家帮忙一下

    定义对象或变量的语句如下:

     // A managed resource that you add in this derived class.
            private ManagedResource addedManaged;
            // A native unmanaged resource that you add in this derived class.
            private NativeResource addedNative;


    田田qq:764574267
    2010年5月11日 3:23

答案

  • 这个问题出现的很正常。因为一旦将 WebBrowser Dispose,那么它就放到待回收队列去了,此时如果再次访问它,CLR 会报一个无法访问已经 Dispose 资源的 Exception。

    当然,Dispose 后有些方法是可以再次访问该对象的,这个就是神奇的对象复活。。。我就不多说了。

    WebBrowser 实际上是 Internet Explorer ActiveX 的一个 Wrapper,用的是 shdocvw.dll。shdocvw.dll 是非托管的。在只有一个 WebBrowser 实例的 Windows Forms 上,Form 的 Dispose 会自动处理 WebBrowser 的 Dispose。不过,如果在一个 Form 上放了多个 WebBrowser (包括动态创建的),这就可能造成内存泄漏。因为非托管资源的回收需要显式调用 Dispose(false)。而这个工作是在 Form 的 Finalizer 完成的。

    一个经典的,也是最好的 Dispose 实现如下:

    public class Form : IDisposable
    {
        public void Dispose()
        {
            this.Dispose(true);
            System.GC.SupressFinalizer(this);
        }

        public virtual void Dispose(bool disposing)
        {
             if (disposing) // 托管资源
            {
            } else {
                // 非托管资源
            }
        }

        ~Form()
        {
            this.Dispose(false);
        }
    }

    可见,非托管资源在窗体的析构函数 (Finalizer) 中被回收。而 Form 的析构函数在窗体/应用程序被关闭时执行。

    我只能解释原理,剩下的如何寻找解决方案,就要看您怎么修改实现了。


    Mark Zhou
    2010年5月12日 9:57

全部回复

  • 这是两个示例而已。因此它只是一个假设的类型名称,并不是已存在的类型。
    Mark Zhou
    2010年5月11日 10:26
  • Dispose要继承Idispose接口! 然后写需要释放哪些类 为null即可
    77138191 .net与asp.net qq群 9861961 silverlight群
    2010年5月11日 15:02
    版主
  •     在程序里是用WebBrower控件定时访问不同的网页,

        程序运行时间越长,占用的内存资源越多,最后所有的内存都用完了,

        程序会报错,提示大概意思是"资源在使用中"

       WebBrower1.Dispose();使用这句想释放内存,但定时器下次触发定时处理事件时,会报不能使用已释放的资源.

        请各位帮一忙,看有没有好的解决办法?


    田田qq:764574267
    2010年5月12日 6:42
  • 你好,遇到此类问题的解决方法是,将该系统类名复制到MSDN中去查询帮助,在显示的帮助信息中即可查看到该类所在的程序集命名空间。

    2010年5月12日 9:29
  • 这个问题出现的很正常。因为一旦将 WebBrowser Dispose,那么它就放到待回收队列去了,此时如果再次访问它,CLR 会报一个无法访问已经 Dispose 资源的 Exception。

    当然,Dispose 后有些方法是可以再次访问该对象的,这个就是神奇的对象复活。。。我就不多说了。

    WebBrowser 实际上是 Internet Explorer ActiveX 的一个 Wrapper,用的是 shdocvw.dll。shdocvw.dll 是非托管的。在只有一个 WebBrowser 实例的 Windows Forms 上,Form 的 Dispose 会自动处理 WebBrowser 的 Dispose。不过,如果在一个 Form 上放了多个 WebBrowser (包括动态创建的),这就可能造成内存泄漏。因为非托管资源的回收需要显式调用 Dispose(false)。而这个工作是在 Form 的 Finalizer 完成的。

    一个经典的,也是最好的 Dispose 实现如下:

    public class Form : IDisposable
    {
        public void Dispose()
        {
            this.Dispose(true);
            System.GC.SupressFinalizer(this);
        }

        public virtual void Dispose(bool disposing)
        {
             if (disposing) // 托管资源
            {
            } else {
                // 非托管资源
            }
        }

        ~Form()
        {
            this.Dispose(false);
        }
    }

    可见,非托管资源在窗体的析构函数 (Finalizer) 中被回收。而 Form 的析构函数在窗体/应用程序被关闭时执行。

    我只能解释原理,剩下的如何寻找解决方案,就要看您怎么修改实现了。


    Mark Zhou
    2010年5月12日 9:57
  • mazhou:您好

    "可见,非托管资源在窗体的析构函数 (Finalizer) 中被回收。而 Form 的析构函数在窗体/应用程序被关闭时执行。"

    我的这个应用程序运行后不关闭,让它一直运行,有两个WebBrower实例,其中一个实例只打开一次网页就不管它了,另一个实例我会定时(现在是5秒)打开一个不同的网页,但随着时间的推移,这个程序占用的内存越来越大,不知道是不是内存泄漏,如果是,应该如果处理?如果要用dispose进行回收,看了你上面的经典例子后,好像是在窗体关闭或程序退出时进行的,但这个程序就这一个窗体,不关闭它,也不退出程序,像这种情况应该如何减少内存占用?


    田田qq:764574267
    2010年5月12日 11:12
  • 其实这里一定存在内存泄漏的,WebBrowser 的行为跟 IE 是保持一致的。利用 GC.Collect() 或者 Dispose 只能回收部分托管资源。对于 IE 泄露的内存则可能无能为力。

    如果窗体一直打开运行,且只有一个 WebBrowser 控件的话,也没什么好优化的了。这里内存泄露的原因主要在于访问的 Web 页。

    您可以做一个简单的试验。打开一 IE,依次输入 10 个 URL 访问 10 个不同的 Web 页,用 Performance Counter 或者 Task Manager 记下每一个 Page 打开后的内存情况。您或许会发现,您的内存使用有增无减。还有,有一些 Web 页使用 AJAX/JavaScript/Timer 获取数据,如果程序代码写得不当,则可能造成更多的内存泄露。

    IE 的内存泄露主要表现在:

    - JavaScript 闭包导致泄露
    - 不恰当的 JavaScript 编码方式导致泄露
    - InnerHTML, AppendChild 的内存泄露
    - 浏览器后退/前进按钮导致的内存泄露

    其实这个问题已经与 Dispose 无关了。要找到 Workaround 的话,您可以先按照我说的做个实验,确保不是由于不同的 Web 页访问导致内存泄露的。


    Mark Zhou
    2010年5月13日 8:53
  • 用一个ie打开不同的网页,内存的确有增无减.
    田田qq:764574267
    2010年5月13日 9:48