因为.NET的垃圾回收机制相当完善,通常情况下我们是不需要关心内存泄漏的。问题人一但傻起来,连自己都会害怕,几个页面跳啊跳的,内存蹭蹭的往上涨,拉都拉不住。这种时候我们就需要冷静下来,泡一杯热巧克力。再打开Visual Studio 2015的Diagnostic Tools,来检查下到底哪段代码出了问题。

  我们先创建一个简单的UWP工程,该工程只有2个几乎为空的Page。MainPage只有两个按钮,分别用来跳转到SecondPage,以及调用GC.Collect()方法。而SecondPage就只有一个Goback用的按钮,同时在SecondPage的构造函数里创建了一个将近400MB的超大ArrayList。

<Page
x:Class="EventMemoryLeak.MainPage"
…… > <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" VerticalAlignment="Center">
<Button Click="Button_Click">Go to second page</Button>
<Button Click="Button_Click_1">Force GC</Button>
</StackPanel>
</Page>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
} private void Button_Click(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(SecondPage));
} private void Button_Click_1(object sender, RoutedEventArgs e)
{
GC.Collect();
}
}
<Page
x:Class="EventMemoryLeak.SecondPage"
…… > <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Click="Button_Click">Go back to main page</Button>
</Grid>
</Page>
public sealed partial class SecondPage : Page
{
public ArrayList arrayList { get; set; } public SecondPage()
{
this.InitializeComponent();
arrayList = new ArrayList();
} private void Button_Click(object sender, RoutedEventArgs e)
{
this.Frame.GoBack();
}
}

  在Visual Studio 2015中Debug UWP程序时,会自动打开Diagnostic Tools的窗口(没打开也没关系,可以通过Debug->Show Diagnostic Tools找到)。

  每从MainPage跳转SecondPage后,内存都会明显的增加。 

  

  在我写下上面这段话之后,再回到运行中的程序,在MainPage点击“Force GC“按钮后,CLR很给面子做了一次彻底的回收,内存占用回到了程序刚打开的状态。这里需要说明的是,调用GC.Collect方法并不能保证立即回收所有引用计数为0的对象且释放所有内存。CLR会自己判断该怎么回收,回收多少,根本就是傲娇的小公举。

  

  那是不是说傲娇的Diagnostic Tools不靠谱呢?非也!首先调用GC.Collect方法,回收是一定会被执行的,必定会有一部分的对象被释放,这部分变化我们可以通过Snapshot很好的进行观察(后面会介绍)。其次,如果确实需要进行比较彻底的回收,根据个人经验,连续调用2到3次GC.Collect方法,效果还是很好的。再傲娇的小公举连续收到“在么”的微信,也会回复“呵呵,睡觉了”意思一下的。

  接下来我们要故意制造严重的内存泄漏,并用Diagnostic Tools来进行观察。我们增加一个Service层的类,并在SecondPage中监听Service层的事件。同时我将SecondPage创建的ArraryList从400MB改为40MB,因为我主打轻薄的笔记本性能无法支撑。

    public class FakeService
{
public static FakeService Instance = new FakeService(); public event EventHandler ShowMeTheMoneyEvent; private FakeService() { }
}
public SecondPage()
{
this.InitializeComponent();
arrayList = new ArrayList();
FakeService.Instance.ShowMeTheMoneyEvent += Instance_ShowMeTheMoneyEvent;
}

  

  这回你会发现,无论你怎么样GC(怎么感觉这个名字有点污……算了我什么都不知道),内存都不会下降了。这是因为SecondPage被FakeService所引用,FakeService又是静态的存活于整个APP生命周期的对象,所以SecondPage再也不会被回收释放了。哎呀我的妈呀……

  先别急着叫,用Snapshot在比较一下内存对象,会有更可怕的事情发生。我们重新运行该程序,在第一次运行到MainPage时,做一次Snapshot。反复的打开3次SeconcdPage,再返回MainPage做第二次的SnapShot。

 

  可以看到对象相对于第一次SnapShot仅增加了43个,但Heap Size已经惨不忍睹了。点击(+43)会打开详细的对象列表。一般情况下,我会在右上角填写命名空间来缩小观察的范围。我们这里会惊讶的发现SecondPage对象,在3次打开该页面后,竟然有3份重复的实例存在。

  点击列表中的SecondPage一行,在屏幕下方的窗口中,会显示Path to Root的相关情况,可以看到SecondPage对象都由EventHandler关联到了FakeService对象上。

  至此,我们通过Diagnostic Tools就找到了内存泄漏的原因,处理方法也很简单,在离开页面时,取消对事件的监听就行了,这里我们可以在页面的OnNavigateFrom方法里来做。

protected override void OnNavigatedFrom(NavigationEventArgs e)

        {

            base.OnNavigatedFrom(e);

            FakeService.Instance.ShowMeTheMoneyEvent -= Instance_ShowMeTheMoneyEvent;

        }

  本篇我们简单的讨论如何使用Diagnostic Tools来观察内存对象,并就监听静态对象的事件引起的内存泄漏举例给出了解决方案。希望能够抛砖引玉,引出许多真知灼见,最不济您也点个推荐呗。

  GayHub:

  https://github.com/manupstairs/UWPSamples/tree/master/UWPSamples/EventMemoryLeak

UWP开发入门(十三)——用Diagnostic Tool检查内存泄漏的更多相关文章

  1. 使用Debug Diagnostic Tool排除内存泄漏故障

    在我之前的博文中(SQL Server内存泄漏),我解释了如何使用“!heap”命令识别哪个模块泄漏了内存.有时我们使用“!d”命令来找到模型或者使用搜索内存命令(s)不能通过显示内存找到原因. 在这 ...

  2. UWP开发入门(十六)——常见的内存泄漏的原因

    本篇借鉴了同事翔哥的劳动成果,在巨人的肩膀上把稿子又念了一遍. 内存泄漏的概念我这里就不说了,之前<UWP开发入门(十三)——用Diagnostic Tool检查内存泄漏>中提到过,即使有 ...

  3. UWP开发入门(四)——自定义CommandBar

    各位好,再次回到UWP开发入门系列,刚回归可能有些不适应,所以今天我们讲个简单的,自定义CommandBar,说通俗点就是自定义类似AppBarButton的东西,然后扔到CommandBar中使用. ...

  4. UWP开发入门系列笔记之(一):UWP初览

    标签: 随着微软Build2015带来的好消息,Win10正式版发布的日子已经离我们越来越近了,我们也终于欣喜地看到:一个统一的Windows平台对于开发人员来说充满了吸引力,这局棋下的好大的说--于 ...

  5. UWP开发入门(十)——通过继承来扩展ListView

    本篇之所以起这样一个名字,是因为重点并非如何自定义控件,不涉及创建CustomControl和UserControl使用的Template和XAML概念.而是通过继承的方法来扩展一个现有的类,在继承的 ...

  6. UWP开发入门(25)——通过Radio控制Bluetooth, WiFi

    回顾写了许久的UWP开发入门,竟然没有讲过通过Windows.Devices.Radios.Radio来控制Bluetooth和WiFi等功能的开关.也许是因为相关的API设计的简单好用,以至于被我给 ...

  7. iOS开发 如何检查内存泄漏

    本文转载至 http://mobile.51cto.com/iphone-423391.htm 在开发的时候内存泄漏是不可避免的,但是也是我们需要尽量减少的,因为内存泄漏可能会很大程度的影响程序的稳定 ...

  8. Android开发之漫漫长途 番外篇——内存泄漏分析与解决

    该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...

  9. 用mtrace检查内存泄漏

    http://blog.csdn.net/ixidof/article/details/6638066内存泄漏检查方法(for Linux) 如果你更想读原始文档, 请参考glibc info的&qu ...

随机推荐

  1. 配置CENTOS YUM更新源

    众所周知,Centos 有个很方便的软件安装工具  yum,但是默认安装完centos,系统里使用的是国外的centos更新源,这就造成了我们使用默认更新源安装或者更新软件时速度很慢的问题. 为了使用 ...

  2. 使用Dezender对zend加密后的php文件进行解密

    在开发中需要修改一些php文件,部分是通过zend加密的,记事本打开之后是这样的: 此时需要使用Dezender进行解密,下载链接如下: Dezender.7z 下载后解压到C盘(路径不要带有中文), ...

  3. retrofit2 上传图片

    直接上代码 接口请求代码 NewResultApi.modifyUserInfo(userModel.getUid(), userModel.getToken(), sex, intro, name, ...

  4. 网页内容导出word/excel的js代码

    IE设置: 工具-> Internet选项-> 安全->自定义级别-> 对没有标记安全级别的ActiveX控件进行初始化  设为启用! 1.导出word //指定区域导出到Wo ...

  5. [转] jQuery对象与DOM对象之间的转换

    http://wozailongyou.iteye.com/blog/299311 http://blog.allenm.me/2009/07/jquery%E4%B8%ADid%E5%92%8Cdo ...

  6. gem install 出现Errno::ECONNRESET: Connection reset by peer - SSL_connect (https://api.rubygems.org

    在安装了rvm来管理多版本的ruby之后,想在不同环境下安装一些gems,结果gem install puma 之后,发现一次又一次失败. gem install 出现Errno::ECONNRESE ...

  7. Django 源码小剖: Django ORM 查询管理器

    ORM 查询管理器 对于 ORM 定义: 对象关系映射, Object Relational Mapping, ORM, 是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.从 ...

  8. 菜鸟学JS(四)——javascript为按钮注册回车事件(设置默认按钮)

    不得不说,在JS方面,自己真的是个不折不扣的菜鸟.对于JS以及一些JS框架如JQuery等JS框架,自己也只是处在简单应用的阶段,当然自己也在不断的学习当中,希望将来能跟大家分享更多JS方面的心得.今 ...

  9. lua中常量的实现及表的深拷贝实现

    废话:好久没在这里写博客了...主要原因是我买了个域名hanxi.info并在github上搭建了个人博客... lua中默认是没有c中的const常量的,在csdn上找到了一个使用setmetata ...

  10. cmd实用命令

    1.netstat 查看电脑端口状况 实际应用举例:查看某软件坚监听的电脑端口. 在任务管理器中选择列...,打开PID的显示.在这里查看某个应用程序的线程ID是多少.例如QQ:4904. 运行,cm ...