首先介绍一下内存泄漏(Memory Leak)的概念,内存泄露是指程序中已动态分配的堆内存由于某种原因未释放或者无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

最近在使用WPF WebBrowser时,就遇到了Memory Leak的问题。

在主窗体上通过一个按钮点击事件加载包含有WebBrowser控件的窗体,使用这个WebBrowser来浏览网页,然后调用WebBrowser的Dispose()方法,然后调用GC.Collect(),最后关闭当前包含有WebBrowser控件的窗体。

通过下面的代码和步骤来还原这个问题。

MainWindow.xaml

    <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Button Content="Launch Browser Window" x:Name="btnLaunchNewWindow" Margin="5,0,5,0" Click="btnLaunchNewWindow_Click" />
<Button Content="Force Garbage Collection" x:Name="btnForceGarbageCollection" Click="btnForceGarbageCollection_Click" />
<Button Content="Quit" x:Name="btnQuit" Click="btnQuit_Click" />
</StackPanel>
        private void btnLaunchNewWindow_Click(object sender, RoutedEventArgs e)
{
new BrowserWindow().Show();
} private void btnForceGarbageCollection_Click(object sender, RoutedEventArgs e)
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect();
} private void btnQuit_Click(object sender, RoutedEventArgs e)
{
Environment.Exit();
}

BrowserWindow.xaml

    <Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions> <StackPanel Orientation="Horizontal">
<Label Content="URL:" />
<TextBox x:Name="txtURL" Width="400" />
</StackPanel> <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,10">
<Button Content="1. Go/Navigate" x:Name="btnGo" Click="btnGo_Click" />
<Button Content="2. Dispose" x:Name="btnClose" Click="btnClose_Click" Margin="10,0" />
<Button Content="3. Force Garbage Collection" x:Name="btnForceGarbageCollection" Click="btnForceGarbageCollection_Click" />
<Button Content="4. Close Window" x:Name="closeWindow" Click="closeWindow_Click" Margin="10,0" />
</StackPanel> <WebBrowser Grid.Row="2" x:Name="webBrowser" />
</Grid>
        private void btnGo_Click(object sender, RoutedEventArgs e)
{
try
{
webBrowser.Navigate(new Uri(txtURL.Text));
}
catch (Exception ex)
{
MessageBox.Show("Exception: " + ex.Message);
}
} private void btnClose_Click(object sender, RoutedEventArgs e)
{
webBrowser.Dispose();
} private void btnForceGarbageCollection_Click(object sender, RoutedEventArgs e)
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.GC.Collect();
} private void closeWindow_Click(object sender, RoutedEventArgs e)
{
this.Close();
}

问题重现步骤:
Step1: 启动程序
Step2: “Launch Browser Window”
Step3: 在地址栏输入 http://www.msn.com (其他网址也可以)
Step4: 点击“1. Go/Navigate” button,
Step5: 当网页加载成功后,点击 “2. Dispose”
Step6: 点击 ”3. Force Garbage Collection”
Step7: 点击“4. Close Window”

重复Step2--Step7 20-25次。

多次测试后的结果如下:
在Step1程序启动后,内存占用在20M左右(不同的机器会有一些差别),

重复Step2--Step7 20-25次之后,程序的内存在130M左右,并且长时间等待不释放。

很不幸运的遇到一个内存泄露的问题。

和大多数WPF控件不一样,WebBrowser控件继承自HwndHost,使用的是非托管的资源,所以对WebBrowser进行Dispose()操作并不管用。

第一种解决方法:

早前使用过WinForm的WebBrowser控件,不存在内存泄露的问题,所以决定使用WinForm的WebBrowser代替WPF的。关于如何在WPF中承载WinForm控件,请参考https://docs.microsoft.com/en-us/dotnet/framework/wpf/advanced/walkthrough-hosting-a-windows-forms-control-in-wpf

第二种解决方法:
依然使用WPF WebBrowser,但是将第二个页面(BrowserWindow.xaml)单独成一个exe。通过主程序去调用,这样当网页浏览完毕后,关闭WebBrowser所在exe,它所关联的内存全部被释放掉了。如果两个程序之间需要通信或者交换数据,可以选用WCF/命名管道等方式。

参考链接:
https://stackoverflow.com/questions/2069314/memory-leak-when-using-wpf-webbrowser-control-in-multiple-windows
https://stackoverflow.com/questions/8302933/how-to-get-around-the-memory-leak-in-the-net-webbrowser-control

WPF WebBrowser Memory Leak 问题及临时解决方法的更多相关文章

  1. WP_Image_Editor_Imagick 漏洞临时解决方法

    导读 阿里云推送的一条短信通知:存放在上面的WordPress程序有WP_Image_Editor_Imagick漏洞问题,需要登入后台补丁等等的暗示.当然,如果需要在线补丁则需要升级阿里云的安骑士专 ...

  2. Myeclipse运行报错:an out of memory error has occurred的解决方法

    不知道怎么了,重装的myeclipse2013,里边就放了一个项目,启动myeclipse就报 an out of memory error has occurred....... 一点yes就退出 ...

  3. (转)苹果iOS开发者账号过期临时解决方法

    苹果iOS开发者账号过期临时解决办法 苹果iOS开发者账号一年的费用是99美金,作者最近由于各种原因,导致renew没能在账号过期之前支付好,所以在账号过期等待renew的期间,试了试一些非正常手段, ...

  4. Win 8下Rime输入法无法同步的临时解决方法

    意外发现了Rime输入法(OS X上叫鼠须管'Squirrel',windows上叫小狼毫'Weasel',linux上叫中州韵'ibus-rime',连名字都起的这么牛逼),真是神器啊,流畅的速度, ...

  5. 使用dnspod遭遇的奇特问题以及背后的原因与临时解决方法

    由于园子里有不少用户在使用dnspod,我们觉得有必要将这两天blogjava.net域名在dsnpod遇到的奇特问题分享一下,以免再有人踩着这个坑. 12月11日,我们登录到dnspod的后台时,大 ...

  6. wordpress后台打开缓慢的临时解决方法

    解决方法是添加下面的主题在目前的代码在functions.php: //禁用Open Sans class Disable_Google_Fonts { public function __const ...

  7. Openwrt flash 空间不足的临时解决方法

    最近有网友在安装软件的时候发现flash空间不够用了: 一个临时的解决方案是在RAM里面使用这个程序.因为 1.路由器改机后的RAM有64MB,flash一般有16MB,RAM空间比较大./tmp是挂 ...

  8. jQuery中的bind绑定事件与文本框改变事件的临时解决方法

    暂时没有想到什么好的解决办法,我现在加了个浏览器判断非ie的话就注册blur事件,这样有个问题就是blur实在别的控件活动焦点的时候,txtStation控件注册的方法是为了填充它紧挨着的一个下拉列表 ...

  9. wpf软件某些分辨率下文字模糊解决方法

    软件测试过程中发现在一台1600*900的分辨率电脑上文字模糊,甚至某些个文字出现压缩扭曲 经过实践,发现按下面方法能解决一点问题: 在窗口或控件上设置字体属性就可以了,如下: <UserCon ...

随机推荐

  1. meta标签属性总结

    一.常见name属性.不同参数含义 meta标签的name属性语法格式是: <meta name="参数" content="具体的参数值"> 其中 ...

  2. Flight学习(一)

    翻看git时看到有新消息提示,点进去第一个就是Flight,那么今天就简单来翻译和了解一下这个框架吧,锻炼下自己的英文文档阅读能力,同时也熟悉下JavaScript.时间太赶,难免出现翻译失误和错误, ...

  3. Java中线程总结

    本文简要介绍在 Java 世界中, 线程相关知识.主要包含 线程的创建与销毁:线程安全与同步:线程通讯:注意本文没有什么高深新知识,只缘起前段时间在翻看项目代码的时候,发现有些同学对此有诸多误解,故在 ...

  4. 小K的H5之旅-HTML5与CSS3部分新属性浅见

    一.HTML部分 1.HTML5新特点 向下兼容.用户至上.化繁为简.无插件范式.访问通用性.引入语义.引入原生媒体支持.引入可编程内容 2.HTML5标签语法 可以省略的元素:空元素语法的元素{br ...

  5. JS 使用 splice() 对数组去重

    一 问题 有如下 js 数组 connect_clients,需要在去掉所有元素中 user_id, goods_id 这两者的值都相同的元素. [ { id: 'eff040fb-92bc-4f24 ...

  6. cpp(第十一章)

    1. std::istream & operator>>(std::istream &is,complex_c &t) { std::cout<<&qu ...

  7. 测序分析软件-phred的安装

    1.进入phred官网,给作者写信,获得所需的软件,大约需要两三天的时间即可收到回信. 2.根据作者的指示下载,解压相应软件. 3.以笔者本人的安装为例unbuntu系统(phred自带的instal ...

  8. C#简单构架之EF进行读写分离+多数据库(Mysql/SqlService)

    最近因为项目需要,研究了下EF的读写分离,所以做了一个demo进行测试,下面是项目的结构 表现层view 主要提供Web.WebApi等表现层的解决方案 公共层public 主要提供项目公共类库,数据 ...

  9. 初学vitmio,vitmio的环境配置及遇到的坑

    1 到官网或者github下载vitamio 官网地址:https://www.vitamio.org/ github地址:https://github.com/yixia/VitamioBundle ...

  10. JS阻塞以及CSS阻塞

    一.JS阻塞 所有的浏览器在下载JS文件的时候,会阻塞页面上的其他活动,包括其他资源的下载以及页面内容的呈现等等,只有当JS下载.解析.执行完,才会进行后面的 操作.在现代的浏览器中CSS资源和图片i ...