关于android:Android-性能优化

0次阅读

共计 5926 个字符,预计需要花费 15 分钟才能阅读完成。

前言

性能优化的过程分两局部:

发现性能瓶颈

制定方案,解决性能问题

解决性能问题的计划须要具体情况具体分析,并没有齐全固定的路子,更多的是靠教训的积攒,本文不做波及。然而发现性能瓶颈的确有着固定的办法。本文次要介绍 如何找到性能瓶颈。

如何找到性能瓶颈

罕用的性能检测工具是 traceview,集成于 Android Device Monitor 中。从 Android Studio3.0 开始,Android Device Monitor 被废除,取而代之的是 Android Profiler,其中提供了 Memory Prodiler、CPU Profiler、Network Prodiler 三大性能。

内存优化(包含内存透露)罕用的是 MAT 或者 LeakCanary,而 Memory Profiler 相当于将 MAT 的简化版性能集成到 AS 中。绝对的在性能优化方面,CPU Profiler 相当于将 traceview 的性能集成到了 AS 中。
所以,应用 AS3.0 之前版本的,能够应用 traceview,而应用 AS3.0 当前版本的,除了 traceview,还能够抉择 CPU Profiler。
如果想追踪零碎过程的具体数据,以解决帧引起的界面卡顿等问题,能够应用 systrace,本文不做波及。

traceview 应用办法

应用 traceview 须要首先应用 Debug 类进行 插桩,当利用执行到被插桩的代码时就会在手机 sdcard 中主动生成 .trace 文件,之后应用 traceview 或者 AS(3.0 以上版本)关上文件即可。

一、插桩

插桩须要应用到 Debug 类,并且会在 sdcard 中生成 .trace 文件,所以你必须首先保障你的利用具备写内部存储(WRITE_EXTERNAL_STORAGE)的权限。

在想要跟踪的代码逻辑结尾和结尾处别离插桩:
// Starts recording a trace log with the name you provide. For example, the

// following code tells the system to start recording a .trace file to the

// device with the name “sample.trace”.

Debug.startMethodTracing(“sample”);

// The system begins buffering the generated trace data, until your

// application calls stopMethodTracing(), at which time it writes

// the buffered data to the output file.

Debug.stopMethodTracing();

生成的 .trace 文件会被保留在固定目录下,与 getExternalFilesDir() 返回的目录雷同,即 /sdcard/Android/data/[YOUR_PACKAGE_NAME]/files 下。
请留神,如果您的利用在未更改跟踪日志名称的状况下再次调用 startMethodTracing(),则会笼罩已保留至设施的现有日志。如果心愿每次运行都保留至不同的日志文件,能够应用如下代码:

// Uses the SimpleDateFormat class to create a String with

// the current date and time.

SimpleDateFormat date =

new SimpleDateFormat(“dd_MM_yyyy_hh_mm_ss”);

String logDate = date.format(new Date());

// Applies the date and time to the name of the trace log.

Debug.startMethodTracing(

“sample-” + logDate);

如果零碎在您调用 stopMethodTracing() 之前达到最大缓冲值,则会进行跟踪并向管理中心发送告诉。开始和进行跟踪的函数在您的整个利用流程内均无效。也就是说,您能够在 Activity 的 onCreate(Bundle)

函数中调用 startMethodTracing(),在 Activity 的 onDestroy() 函数中调用 stopMethodTracing()。

二、查看 .trace 文件

插好桩后,装置利用并运行被检测局部的性能,而后就能够通过 AS 或者 traceview 查看文件了。

应用 AS 查看

在 AS 中点击 View – Tool Windows – Android File Explorer 关上 Android File Explorer:

在 /sdcard/Android/data/[YOUR_PACKAGE_NAME]/files 下即可找到生成的 .trace 文件,双击文件即可关上。

将 .trace 文件保留至电脑,间接拖入 AS 窗口,也可间接关上该视图。

在关上的视图中,左上方能够抉择想要查看的线程。能够查看监控期间指定线程运行了多久、执行了哪些办法、每个办法执行了多久等等。

其中有 4 个名词须要解释一下:

  • Wall Clock Time:壁钟工夫,示意理论通过的工夫,即进入某个办法到退出该办法的工夫,不思考线程是流动还是休眠状态。
  • Thread time:线程工夫,示意理论通过的工夫减去线程没有耗费 CPU 资源(处于休眠)的工夫局部。对于任何给定函数,其线程工夫始终少于或等于其壁钟工夫。应用线程工夫能够让您更好地理解线程的理论 CPU 使用率中有多少是给定函数耗费的。
  • Inclusive Time:办法执行本人代码的工夫 + 执行本人 child 办法的工夫。
  • Exclusive Time:办法执行本人代码的工夫。

应用 traceview 查看

要应用 traceview 查看,须要首先将 .trace 文件保留到电脑:

adb pull /sdcard/Android/data/[YOUR_PACKAGE_NAME]/files/sample.trace D:\Documents\sample.trace

关上 Android Device Monitor。AS3.0 以前的版本,就是 LogCat 所在的窗口,再切换一下 tab 页即可。AS3.0 当前,进入 android-sdk/tools/ 门路,运行以下命令:

monitor

尽管 Android Device Monitor 的 DDMS 也有 File Explorer,然而未 root 的手机,查看不到上述门路,因而只能将 .trace 文件保留到电脑查看。

在 Android Device Monitor 中,顺次点击 File - Open File,抉择 .trace 文件门路即可关上:

内容与 AS 关上时相似,相差较大的次要是图标局部,没有 AS 的 Call Chart 直观形象。

其中也有 4 个概念:

Cpu Time:相当于 AS 中的 Thread time。

Real Time:相当于 AS 中的 Wall Clock Time。

Inclusive Time:同 AS 一样。

Exclusive Time:同 AS 一样。

应用 AS 查看还是应用 traceview 查看

这个就见仁见智了,依据我集体应用的感觉来看,倡议应用 AS 查看。起因有二:

AS 更简略。不须要独自关上 ADM,更不须要将 .trace 文件保留到电脑。

AS 的调用图(Call Chart)更加直观,cpu 工夫的耗费高深莫测。

Call Chart 的程度轴示意函数调用(或调用方)的时间段和工夫,并沿垂直轴显示其被调用者。下图展现了一个调用图表示例,并描述了给定函数的 self time、children time 以及总工夫的概念。

最初须要留神一点,跟踪剖析过程中,利用的运行速度会减慢。所以,通过 traceview 失去的剖析数据并不能准确反馈某个办法在理论执行时的相对工夫。对于这一点,在最初的注意事项中再做详细分析。

Google 还提供了基于样本的剖析形式,以缩小剖析对运行时性能的影响。要启用样本剖析,需调用 Debug.startMethodTracingSampling() 办法(而非 Debug.startMethodTracing() 办法)。零碎会定期收集样本,直至调用 stopMethodTracing()。

CPU Profiler 应用办法

应用 CPU Profiler 进行函数跟踪比 traceview 更简略。不须要做任何代码上的植入,上面做一个简略的介绍:

首先,通过

View – Tool Windows – Android Profiler 关上 Android Profiler。手机连贯电脑后运行利用,在 Android Profiler 中会看到以下视图:

左上角能够抉择设施和过程,点击 CPU 区域,即可进入 CPU Profiler 视图:

左上角能够抉择跟踪模式:

Sampled:按默认采样率捕捉利用的调用堆栈。该模式的固有问题是,如果利用在一次捕捉后进入一个函数并在下一次捕捉前退出该函数,则分析器不会记录该函数调用。如果对此类生命周期很短的跟踪函数感兴趣,能够应用“Instrumented”跟踪。

Instrumented:以在每个函数调用的开始和完结时记录时间戳。剖析比拟工夫戳,以生成函数跟踪数据。须要留神的是,设置与函数关联的开销会影响运行时性能,甚至剖析数据,对于生命周期绝对较短的函数,这一点更为显著。此外,如果利用短时间内执行大量函数,则分析器可能会迅速超出它的文件大小限度,且不能再记录更多跟踪数据。

Edit configurations:自定义采样率。与 traceview 中的 Debug.startMethodTracingSampling() 相似。

.trace 文件的大小是有限度的。对于给定录制,当分析器达到该限度时,AS 将进行收集新数据(不过,这不会进行记录)。在执行“Instrumented”跟踪时,这种状况通常会更快产生,因为与“Sampled”跟踪相比,此类跟踪在较短时间里会收集更多数据。

如果你应用的是 Android 8.0(API 26)或更高版本的设施,则对于跟踪数据的文件大小没有限度,此值可疏忽。不过,你仍需注意每次记录后设施收集了多少数据,因为 AS 可能难以解析大型跟踪文件。

点击上方的“开始录制”按钮,而后在利用中操作执行被追踪的性能,完结后再点击“进行录制”按钮。CPU Profiler 会主动开始剖析并生成数据。

以上就是 CPU Profiler 和 traceview 的应用办法。至于如何制订优化计划,就不开展了,并没有齐全固定的路子。就我本例的 onRebuild() 办法而言,是针对耗时的 Contact 结构过程做了并行处理,将上百个有序的结构过程平分到 5 个线程中并发执行,而后再按程序合并数据到一个线程中。最终 onRebuild() 执行速度从 15 秒晋升到了 2.5 秒,对我来说曾经够用了。

重要注意事项

无论是应用 traceview 还是 CPU Profiler 进行函数跟踪,有一点须要留神:跟踪剖析过程中,利用的运行速度会减慢。所以,剖析数据并不能准确反馈某个办法在理论执行时的相对工夫。上面是我在优化我的项目中的 onRebuild(boolean) 办法时,记录的 4 组数据,让咱们来比照一下:

理论执行工夫:不启用剖析模式,失常运行状态下通过打印日志失去的理论执行工夫。

Profiler 统计工夫:应用 CPU Profiler 剖析取得的执行工夫。

traceview 统计工夫:通过剖析 traceview 产生的 .trace 文件,从中取得的执行工夫。

traceview 理论工夫:应用 traceview 的状况下,通过打印日志失去的理论执行工夫。

为什么针对 traceview 会例举两个工夫呢?这是因为测试过程中发现 traceview 主动剖析进去的工夫比 理论执行工夫 不仅没有慢,反而快了很多,纳闷下又在启用 traceview 的状况下通过以下代码测算了一下理论的工夫,这个倒是真的比 理论执行工夫 慢了。

Debug.startMethodTracing(“smssdk_onrebuild”);

long curr = System.currentTimeMillis();

onRebuild(true);

Log.d(TAG, “onRebuild lasts: ” + (System.currentTimeMillis() – curr));

Debug.stopMethodTracing();

从上表数据可见,无论是 CPU Profiler 还是 traceview,

统计进去的工夫都不能精确代表理论执行工夫。更甚者,traceview 主动剖析进去的数据也与 traceview 跟踪模式下理论的工夫有微小差异,对于这一点,我没找到具体的解释,如果有人晓得,还望不吝赐教。
既然跟踪剖析失去的工夫都不能示意理论的工夫,那么这些数据是不是没用呢?当然不是!它们至多在以下两个方面具备价值:

  • 在一次检测失去的数据中,线程内各个办法执行所耗时间在整个线程执行工夫中所占比例具备肯定参考价值。占比高的办法当是优化的重点指标。
  • 优化前后两次检测失去的数据,有比拟价值,以确认优化计划是否真的失效。

通过这些工具跟踪函数,也只能做一个绝对的参考,并不能完全正确的反馈函数的执行性能。比方我通过 CPU Profiler 取得的 onRebuild() 办法的剖析数据显示,整个执行过程中 Contact 的构造方法占了 60% 左右,Contact.toString() 办法占了 40% 左右,但实际上在 onRebuild() 办法耗费的 15 秒中,Contact.toString() 只耗费了百毫秒级,而九成以上工夫都被其构造方法耗费了,阐明 CPU Profiler 的监控过程对 Contact.toString() 的性能产生了更大的影响。

而同样的问题却并没有呈现在 traceview 的剖析后果中。

请留神,CPU Profiler 和 traceview 不能同时应用,如果代码中植入了插桩的代码,则有可能导致 CPU Profiler 无奈失常开始或进行录制。

traceview 和 CPU Profiler 的比照

从用法上来看,traceview 比 CPU Profiler 略微简单一点。相似于 MAT 须要首先获取 .hprof 堆转储文件,traceview 也要首先获取 .trace 文件,而后应用 traceview 剖析该文件。而 CPU Profiler 则能够间接对利用进行剖析。

从最终生成的图表上来看,CPU Profiler 生成的图表有 Call Chart、Flame Chart,它们能够十分形象的示意出线程内执行了哪些函数,函数的执行工夫,调用栈等等,高深莫测,而且在任意函数上点击右键,能够间接跳转至对应的代码,十分不便,在这一点上,绝对于 traceview 要优良。

正文完
 0