UWP开发入门(十三)——用Diagnostic Tool检查内存泄漏

简介: 原文:UWP开发入门(十三)——用Diagnostic Tool检查内存泄漏  因为.NET的垃圾回收机制相当完善,通常情况下我们是不需要关心内存泄漏的。问题人一但傻起来,连自己都会害怕,几个页面跳啊跳的,内存蹭蹭的往上涨,拉都拉不住。
原文: UWP开发入门(十三)——用Diagnostic Tool检查内存泄漏

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

  我们先创建一个简单的UWP工程,该工程只有2个几乎为空的PageMainPage只有两个按钮,分别用来跳转到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(100000000);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.Frame.GoBack();
        }
    }

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

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

  

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

  

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

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

    public class FakeService
    {
        public static FakeService Instance = new FakeService();

        public event EventHandler ShowMeTheMoneyEvent;

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

 

  

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

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

目录
相关文章
|
11天前
|
开发工具 Swift iOS开发
【Swift开发专栏】Swift中的内存泄漏检测与修复
【4月更文挑战第30天】本文探讨了Swift中的内存泄漏问题,尽管有ARC机制,但仍需关注内存管理。文章分为三部分:内存管理基础知识、检测方法和修复技巧。了解ARC原理和循环引用陷阱是防止内存泄漏的关键。检测方法包括使用Xcode内存调试器、LeakSanitizer和性能分析工具。修复技巧涉及打破循环引用、使用弱/无主引用及手动管理内存。理解这些对优化应用性能和稳定性至关重要。
|
11天前
|
Web App开发 缓存 前端开发
【Flutter前端技术开发专栏】Flutter中的性能优化与内存管理
【4月更文挑战第30天】本文探讨了Flutter应用的性能优化和内存管理。关键点包括:减少布局重绘(使用`const`构造函数和最小化依赖),选择合适的动画实现,懒加载和按需加载以提升性能。同时,强调了避免内存泄漏和优化内存使用,利用Flutter提供的性能分析工具。实践案例展示了如何优化ListView,包括使用`ListView.builder`和缓存策略。通过这些方法,开发者可以提升应用的响应性、流畅性和稳定性。
【Flutter前端技术开发专栏】Flutter中的性能优化与内存管理
|
4天前
|
安全 Linux Python
Volatility3内存取证工具安装及入门在Linux下的安装教程
Volatility3内存取证工具安装及入门在Linux下的安装教程
Volatility3内存取证工具安装及入门在Linux下的安装教程
|
4天前
|
数据安全/隐私保护 Python Windows
Volatility2.6内存取证工具安装及入门-2
Volatility2.6内存取证工具安装及入门
Volatility2.6内存取证工具安装及入门-2
|
4天前
|
安全 Python Linux
Volatility2.6内存取证工具安装及入门-1
Volatility2.6内存取证工具安装及入门
Volatility2.6内存取证工具安装及入门-1
|
11天前
|
存储 Java Android开发
安卓应用开发中的内存优化策略
【4月更文挑战第30天】在移动开发领域,尤其是安卓平台上,内存管理是影响应用性能和用户体验的关键因素。由于安卓设备的硬件资源有限,不合理的内存使用会导致应用响应缓慢、消耗过多电量甚至崩溃。本文将探讨针对安卓平台的内存优化技巧,旨在帮助开发者提高应用的性能和稳定性,从而提升用户满意度。我们将详细讨论内存泄漏的预防、合理的内存分配策略以及高效的内存回收方法。
|
11天前
|
Dart 前端开发 Java
【Flutter前端技术开发专栏】Flutter中的内存泄漏检测与解决
【4月更文挑战第30天】本文探讨了Flutter应用中的内存泄漏检测与解决方法。内存泄漏影响性能和用户体验,常见原因包括全局变量、不恰当的闭包使用等。开发者可借助`observatory`工具或`dart_inspector`插件监测内存使用。解决内存泄漏的策略包括避免长期持有的全局变量、正确管理闭包、及时清理资源、妥善处理Stream和RxDart订阅、正确 disposal 动画和控制器,以及管理原生插件资源。通过这些方法,开发者能有效防止内存泄漏,优化应用性能。
【Flutter前端技术开发专栏】Flutter中的内存泄漏检测与解决
|
11天前
|
Swift 开发者
【Swift开发专栏】Swift中的内存管理ARC机制
【4月更文挑战第30天】Swift的Automatic Reference Counting (ARC)自动管理内存,通过跟踪对象引用实现对象的释放。当引用计数为0时,系统回收内存。引用计数在变量赋值时增加,引用移除时减少。循环引用可能导致内存泄漏,Swift通过weak(可选)和unowned(非空)引用解决此问题,根据对象生命周期选择合适类型。理解ARC和正确处理循环引用是关键。
|
12天前
|
监控 Java Android开发
安卓应用开发中的内存优化策略
【4月更文挑战第29天】在面对安卓设备多样化的硬件配置时,合理管理应用内存成为提升用户体验的关键。本文深入探讨了安卓应用开发中常见的内存泄漏问题,并提出了一系列针对性的优化策略。通过分析内存分配机制、垃圾回收原理及内存监控工具的使用,揭示了高效内存管理的实践方法。文章旨在为开发者提供一套系统的内存优化解决方案,以实现更流畅、稳定的应用性能。
|
13天前
|
监控 Linux
【专栏】在 Linux 中,掌握检查内存使用情况至关重要,因为内存问题可能导致系统性能下降甚至崩溃。这 5 个命令堪称绝了!
【4月更文挑战第28天】在 Linux 中,掌握检查内存使用情况至关重要,因为内存问题可能导致系统性能下降甚至崩溃。本文介绍了 5 个常用的检查内存命令:1) `free` 提供内存和交换区的详细信息;2) `top` 显示进程信息及内存使用;3) `vmstat` 输出系统综合信息,包括内存动态变化;4) `pidstat` 监控特定进程的内存使用;5) `/proc/meminfo` 文件提供系统内存详细数据。了解和使用这些命令能帮助用户及时发现并解决内存相关问题,确保系统稳定运行。