Xamarin.Forms之跨平台性能
1、使用 Profiler
Profiling是一种用于确定代码优化在减少性能问题方面将发挥最大作用的技术。 探查器跟踪应用程序的内存使用情况,并记录应用程序中方法的运行时间。 这些数据有助于在应用程序的执行路径和代码的执行成本之间导航,从而可以发现最佳的优化机会。
Xamarin Profiler 简介。
分析应用时建议采用以下最佳做法:
- 使用真机测试,而不是用模拟器,因为模拟器可能误报应用程序性能。
- 使用多种不同型号 不同配置的真机测试。
- 关闭所有其他应用程序,减少不必要的干扰。
从历史上看,Mono具有功能强大的命令行分析器,用于收集有关在Mono运行时中运行的程序的信息,称为Mono日志分析器。 Xamarin Profiler是Mono日志探查器的图形界面,并支持对Mac上的Android,iOS,tvOS和Mac应用程序以及Windows上的Android,iOS和tvOS应用程序进行性能分析。
Xamarin Profiler有许多可用于性能分析的工具:分配、周期和时间分析器。 下面探讨了这些工具的测量内容以及它们如何分析您的应用程序,并阐明了每个屏幕上显示的数据的含义。
1.1、下载和安装
Xamarin Profiler是一个独立的应用程序,并且与Visual Studio for Mac和Visual Studio集成在一起,从而可以在IDE中进行性能分析。
下载适合您平台的安装软件包:
- macOS
- Windows
下载完成后,启动安装程序以将Xamarin Profiler添加到您的系统。
选择Android或者ios程序,在分析菜单中:
1.2、Profilers and Profiling
Profiling是应用程序开发中的一个重要且通常被忽略的步骤,Profiling是动态程序分析的一种形式-它在程序运行和使用时对其进行分析。
Profiler是一种数据挖掘工具,它收集有关时间复杂性,特定方法的使用以及分配的内存的信息,Profiler使您能够深入研究和分析这些指标,以查明代码中的问题区域。
在设计和开发应用程序时,不要过早优化很重要; 也就是说,将时间花在很少访问的区域上来开发代码,这就是分析的力量。 探查器可洞悉代码库中最常用的部分,并帮助您确定应花时间进行改进的区域,开发人员应注意了解大部分时间在应用程序中所花的时间,以及应用程序如何使用内存。
概要分析对所有类型的开发都有帮助,但在移动开发中尤其重要。 在移动平台上,未优化的代码比在台式机上更加引人注目,而您的应用能否成功取决于能否有效运行的美观且经过优化的代码。
分析方法:
使用Xamarin Profiler剖析应用程序的方法有多种,包括内存剖析和统计采样,这些分别通过“分配”和“时间分析器”工具执行。
探查器是与VS是分开的进程,因此,除了从Visual Studio中启动之外,它还可以用作独立的应用程序,以检查由mono log profiler生成的.exe和.mlpd文件。
注: you can only profile Debug configurations
1.3、Profiler Basics
在成功对应用程序进行配置文件之前,您需要在应用程序的“项目选项”中允许“Profiling”
安装Profiler后,Android程序默认可以打开Xamarin.Profiler了,而IOS程序需要在项目属性中设置:
它通过分配和时间探查器检测来实现此目标,我们将在下一节将对此进行详细探讨。
保存和加载探查器会话
这会将文件保存为 .mlpd_格式,这是一种特殊的高度压缩格式,用于分析数据。
安装后,可以在应用程序目录中找到 Xamarin Profiler 应用程序:
.mlpd文件加载到探查器中。
1.4、探查器功能
Xamarin Profiler 由五个部分组成,
- 工具栏-位于探查器顶部,这提供了启动/停止分析、选择目标进程、查看应用程序运行时间以及组成探查器应用程序的拆分视图的选项。
- 检测列表–列出了为分析会话加载的所有工具。
- 可以使用滑块(在时间探查器下显示)来更改刻度。
- 在下面的部分中,我们将更详细地介绍这些视图。
- 这些部分依赖于所选乐器,并包括:配置设置、统计信息、堆栈跟踪信息和根的路径。
1.4.1、分配
分配工具在创建和收集垃圾时提供有关应用程序中对象的详细信息。
探查器的顶部是分配图,该图显示了性能分析期间按固定间隔分配的内存量。 当前,分配图是分配的总数,而不是该时间点的堆大小。 从某种意义上说,它将永远不会下降,只会不断增加,这包括分配在堆栈上的对象。 根据使用的运行时版本,图表可能看起来有所不同-即使对于同一应用程序也是如此。
分配工具中有不同的数据视图,使开发人员可以分析其应用程序如何使用和释放内存。 这些视图如下所述:
- 双击类将显示分配的内存:
检查器的“分配”视图提供用于对对象进行过滤和分组的选项,提供有关已分配内存和最高分配的统计信息,以及“堆栈跟踪”和“根路径”的视图。
- 调用树:显示应用程序中所有线程的整个调用树,并包括有关在每个节点上分配的内存的信息。 在列表中选择一个元素时,所有同级节点将显示为灰色。 您可以展开树或双击该元素以对其进行深入研究。显示此数据视图时,可以使用显示设置检查器视图来更改其显示方式。 当前有两种选择:
反向调用树–这从上到下考虑堆栈跟踪。 这是一个方便的视图选项,因为它指示CPU花费时间的最深层方法。
按线程分隔–此选项按线程组织调用树。
- 请注意,仅当实时分析应用程序时,才可以执行快照。
1.4.2、时间分析器
Time Profiler仪器精确地测量在应用程序中每个方法花费了多少时间。 应用程序会定期暂停,并在每个活动线程上运行堆栈跟踪。 检测详细信息区域中的每一行都显示了已遵循的执行路径。
如下图的屏幕截图所示,该绘图图显示了该应用在运行时收到的样本数量:
"调用树"-显示每个方法所用的时间量。
1.4.3、循环
此检测允许你查找这些对象,并显示应用程序中引用的循环。
2、释放 IDisposable 资源
IDisposable接口提供了一种释放资源的机制,它提供了Dispose方法,应实现该方法以显式释放资源,IDisposable不是析构函数,仅应在以下情况下实现:
- 当类拥有非托管资源时,需要释放的典型非托管资源包括文件,流和网络连接。
- 当类拥有托管IDisposable资源时。
然后,类型使用者可以调用IDisposable.Dispose实现以在不再需要该实例时释放资源。 有两种方法可以实现此目的:
- 通过将IDisposable对象包装在using语句中。
- 通过将对IDisposable的调用包装起来,放在try / finally块中。
在 using 语句中包装 IDisposable 对象
public void ReadText (string filename) { ... string text; using (StreamReader reader = new StreamReader (filename)) { text = reader.ReadToEnd (); } ... }
StreamReader类实现IDisposable,并且using语句提供了一种方便的语法,该语法在超出范围之前在StreamReader对象上调用StreamReader.Dispose方法。 在using块中,StreamReader对象是只读的,无法重新分配。 using语句还确保即使发生异常也可以调用Dispose方法,因为编译器为try / finally块实现了中间语言(IL)。
在 Try/Finally 块中包装对 IDisposable.Dispose 的调用
public void ReadText (string filename) { ... string text; StreamReader reader = null; try { reader = new StreamReader (filename); text = reader.ReadToEnd (); } finally { if (reader != null) { reader.Dispose (); } } ... }