Winforms:消除WebBrowser的GDI Objects泄露

Winforms的WebBrowser是一个经常被使用的控件,用来浏览网页。可是很多程序员发现WebBrowser会有GDI Objects泄露。

一、             问题重现步骤

  1. 新建一个Winforms项目;
  2. 添加一个新Form,命名为FormWebBrowser;
  3. 在FormWebBrowser中添加一个WebBrowser,并为属性Url设置一个有效的网址;
  4. 回到Form1,在上面添加一个按钮;
  5. 双击按钮,进入代码编辑窗口;
  6. 为button1的Click添加事件处理器:

private void button1_Click(object sender, EventArgs e)

{

    FormWebBrowser form = new FormWebBrowser();

    form.ShowDialog();

}

  1. 编译运行;
  2. 打开任务管理器。如果进程(Processes)页面没有GDI Objects的列,点击菜单视图 (View)->选择列(Select Column…)。在弹出的对话框中,选择GDI Objects;
  3. 点击button1,这样FormWebBrowser就会弹出来。关掉FormWebBrowser,回到Form1。再点击button1。这样重复弹出FormWebBrowser再关掉。
  4. 在步骤9中,注意每次关掉FormWebBrowser时GDI Objects数目。我们会注意到GDI Objects数目会一直升高。这就是GDI Objects的症状。

二、             原因分析

为了正确显示网页的内容,WebBrowser会创建一些GDI的对象。GDI对象不是托管资源,因此当我们不再需要这些资源时,我们应该显示释放这些资源。WebBrowser提供了Dispose函数,在WebBrowser不再使用的时候,我们应该调用Dispose函数。

三、             建议

既然出现GDI Objects泄露的原因是没有调用WebBrowser.Dispose(),我们就应该在合适的时候调用这个方法。显然,我们在FormWebBrowser消失的时候,我们不会再使用WebBrowser,这个时候就可以调用该方法。也就是我们可以在FormWebBrowser的Closed事件处理器里调用WebBrowser.Dispose。

事实上Form也有Dispose方法。在Form.Dispose里,Winforms会去调用它所有子控件的Dispose方法。因此,一个更安全的办法就是当FormWebBrowser不再使用的时候,调用FormWebBrowser.Dispose。

C#提供了using的关键词。使用这个关键词创建的对象,.NET会确保在这些对象不再使用的时候会调用它们的Dispose。这样会比我们自己调用Dispose会更安全。

基于上面的分析,我们建议的办法是:我们用using关键词创建FormWebBrowser 对象。这样当我们关掉一个FormWebBrowser的时候,我们会确保它的Dispose会被调用。这样WebBrowser的Dispose也会被调用,GDI的资源也就随之释放,也就没有GDI的泄露了。

参考代码如下:

    private void button1_Click(object sender, EventArgs e)

    {

        using (FormWebBrowser form = new FormWebBrowser())

            form.ShowDialog();

    }

posted on 2010-06-19 12:26  rxie  阅读(906)  评论(0编辑  收藏  举报