首先介绍一下内存泄漏(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. Linux_破解密码-营救模式

    实验用机:CentOS 5.7 破解密码 设置开机启动界面 系统运行级别 营救模式 一.破解密码 root用户可以更改任何用户的密码,普通用户只能修改自己的密码. 步骤: 1.重新启动系统 2.开机倒 ...

  2. [原创]nagios搭建配置

    nagios搭建配置 一.环境 ubuntu 14.04系统 host1:172.17.0.2 serverhost2:172.17.0.3 client 二.安装 1.在两个主机上都执行一下命令: ...

  3. DATA VISUALIZATION – PART 2

    A Quick Overview of the ggplot2 Package in R While it will be important to focus on theory, I want t ...

  4. Deep Learning in R

    Introduction Deep learning is a recent trend in machine learning that models highly non-linear repre ...

  5. IT培训行业揭秘(六)

    2017年全国的IT职业培训机构的招生数量相比于去年同期都出现了大规模的下滑,虽然目前大学生毕业之后参加培训班的人数依然没有变化,但是目前中小培训机构像雨后春笋般的纷纷建立,他们纷纷抢占市场,为了招生 ...

  6. sql备份(.bak文件备份)

    第一步: 右键需要备份的数据库(这里以 MyDB 为例)-->任务-->备份

  7. struts2+hibernate+spring注解版框架搭建以及简单测试(方便脑补)

    为了之后学习的日子里加深对框架的理解和使用,这里将搭建步奏简单写一下,目的主要是方便以后自己回来脑补: 1:File--->New--->Other--->Maven--->M ...

  8. react-router 参数获取

    No BB!!! show me the code. Main.js import { BrowserRouter, Route, Link ,Switch} from 'react-router-d ...

  9. 浅谈JavaScript递归

    递归:是指函数/过程/子程序在运行过程序中直接或间接调用自身而产生的重入现象.递归指的是一个过程:函数不断引用自身,直到引用的对象已知. //公园里面有200个桃子,每天吃掉一半,扔掉一个烂的,第6天 ...

  10. ui-router 父子state共享数据

    如果ui-view是嵌套的,那么在子view中,可以直接引用 $scope.$parent 即可.