• 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

  • 相关阅读:
    ztree
    SAMEORIGIN
    Unity shader学习之折射
    Unity shader学习之反射
    Unity shader学习之标准的Unity shader
    Unity shader学习之Alpha Test的阴影
    Unity shader学习之阴影,衰减统一处理
    Unity shader学习之阴影
    Unity shader学习之Forward Rendering Path
    AsyncClientUtils
  • 原文地址:https://www.cnblogs.com/manupstairs/p/5493399.html
Copyright © 2020-2023  润新知