Android APP 性能优化

说到 Android 系统手机,大部分人的印象是用了一段时间就变得有点卡顿,有些程序在运行期间莫名其妙的出现崩溃,打开系统文件夹一看,发现多了不少文件,而后用手机管家 APP 不断地进行清理优化 ,才感受运行速度稍微提升了点,就算手机在各类性能跑分软件面前分数遥遥领先,仍是感受不管有多大的内存空间都远远不够用。相信每一个使用 Android 系统的用户都有过以上相似经历,确实,Android 系统在流畅性方面不如 IOS 系统,为什么呢,明明在看手机硬件配置上时,Android 设备都不会输于 IOS 设备,甚至都强于它,关键是在于软件上。形成这种现象的缘由是多方面的,简单罗列几点以下:程序员

  • 其实近年来,随着 Android 版本不断迭代,Google 提供的Android 系统已经愈来愈流畅,目前最新发布的版本是 Android 8.0 Oreo 。可是在国内大部分用户用的 Android 手机系是各大厂商定制过的版本,每每不是最新的原生系统内核,可能绝大多数还停留在 Android 5.0 系统上,甚至 Android 6.0 以上所占比例还偏小,更新存在延迟性。
  • 因为 Android 系统源码是开放的,每一个人只要听从相应的协议,就能够对源码进行修改,那么国内各个厂商就把基于 Android 源码改形成本身对外发布的系统,好比咱们熟悉的小米手机 Miui 系统、华为手机 EMUI 系统、Oppo 手机 ColorOS 系统等。因为每一个厂商都修改过 Android 原生系统源码,这里面就会引起一个问题,那就是著名的Android 碎片化问题,本质就是不一样 Android 系统的应用兼容性不一样,达不到一致性。
  • 因为存在着各类 Android 碎片化和兼容性问题,致使 Android 开发者在开发应用时须要对不一样系统进行适配,同时每一个 Android 开发者的开发水平良莠不齐,写出来的应用性能也都存在不一样类型的问题,致使用户在使用过程当中用户体验感觉不一样,那么有些问题用户就会转化为 Android 系统问题,进而影响对Android 手机的评价。

性能优化

今天想说的重点是Android APP 性能优化,也就是在开发应用程序时应该注意的点有哪些,如何更好地提升用户体验。一个好的应用,除了要有吸引人的功能和交互以外,在性能上也应该有高的要求,即时应用很是具备特点,在产品前期可能吸引了部分用户,可是用户体验很差的话,也会给产品带来很差的口碑。那么一个好的应用应该如何定义呢?主要有如下三方面:canvas

  • 业务/功能
  • 符合逻辑的交互
  • 优秀的性能

众所周知,Android 系统做为以移动设备为主的操做系统,硬件配置是有必定的限制的,虽然配置如今愈来愈高级,但仍然没法与 PC 相比,在 CPU 和内存上使用不合理或者耗费资源多时,就会碰到内存不足致使的稳定性问题、CPU 消耗太多致使的卡顿问题等。缓存

面对问题时,你们想到的都是联系用户,而后查看日志,但却不知有关性能类问题的反馈,缘由也很是难找,日志大多用处不大,为什么呢?由于性能问题大部分是非必现的问题,问题定位很难复现,而又没有关键的日志,固然就没法找到缘由了。这些问题很是影响用户体验和功能使用,因此了解一些性能优化的一些解决方案就显得很重要了,并在实际的项目中优化咱们的应用,进而提升用户体验。性能优化

四个方面

能够把用户体验的性能问题主要总结为4个类别:服务器

  • 流畅
  • 稳定
  • 省电、省流量
  • 安装包小

性能问题的主要缘由是什么,缘由有相同的,也有不一样的,但归根到底,不外乎内存使用、代码效率、合适的策略逻辑、代码质量、安装包体积这一类问题,整理归类以下:网络

性能优化图

从图中能够看到,打造一个高质量的应用应该以4个方向为目标:快、稳、省、小。数据结构

快:使用时避免出现卡顿,响应速度快,减小用户等待的时间,知足用户指望。架构

稳:减低 crash 率和 ANR 率,不要在用户使用过程当中崩溃和无响应。框架

省:节省流量和耗电,减小用户使用成本,避免使用时致使手机发烫。异步

小:安装包小能够下降用户的安装成本。

要想达到这4个目标,具体实现是在右边框里的问题:卡顿、内存使用不合理、代码质量差、代码逻辑乱、安装包过大,这些问题也是在开发过程当中碰到最多的问题,在实现业务需求同时,也须要考虑到这点,多花时间去思考,如何避免功能完成后再来作优化,否则的话等功能实现后带来的维护成本会增长。

卡顿优化

Android 应用启动慢,使用时常常卡顿,是很是影响用户体验的,应该尽可能避免出现。卡顿的场景有不少,按场景能够分为4类:UI 绘制、应用启动、页面跳转、事件响应,如图:

卡顿场景

这4种卡顿场景的根本缘由能够分为两大类:

  • 界面绘制。主要缘由是绘制的层级深、页面复杂、刷新不合理,因为这些缘由致使卡顿的场景更多出如今 UI 和启动后的初始界面以及跳转到页面的绘制上。
  • 数据处理。致使这种卡顿场景的缘由是数据处理量太大,通常分为三种状况,一是数据在处理 UI 线程,二是数据处理占用 CPU 高,致使主线程拿不到时间片,三是内存增长致使 GC 频繁,从而引发卡顿。

引发卡顿的缘由不少,但无论怎么样的缘由和场景,最终都是经过设备屏幕上显示来达到用户,归根到底就是显示有问题,因此,要解决卡顿,就要先了解 Android 系统的显示原理。

Android系统显示原理

Android 显示过程能够简单归纳为:Android 应用程序把通过测量、布局、绘制后的 surface 缓存数据,经过 SurfaceFlinger 把数据渲染到显示屏幕上, 经过 Android 的刷新机制来刷新数据。也就是说应用层负责绘制,系统层负责渲染,经过进程间通讯把应用层须要绘制的数据传递到系统层服务,系统层服务经过刷新机制把数据更新到屏幕上。

咱们都知道在 Android 的每一个 View 绘制中有三个核心步骤:Measure、Layout、Draw。具体实现是从 ViewRootImp 类的performTraversals() 方法开始执行,Measure 和 Layout都是经过递归来获取 View 的大小和位置,而且以深度做为优先级,能够看出层级越深、元素越多、耗时也就越长。

真正把须要显示的数据渲染到屏幕上,是经过系统级进程中的 SurfaceFlinger 服务来实现的,那么这个SurfaceFlinger 服务主要作了哪些工做呢?以下:

  • 响应客户端事件,建立 Layer 与客户端的 Surface 创建链接。
  • 接收客户端数据及属性,修改 Layer 属性,如尺寸、颜色、透明度等。
  • 将建立的 Layer 内容刷新到屏幕上。
  • 维持 Layer 的序列,并对 Layer 最终输出作出裁剪计算。

既然是两个不一样的进程,那么确定是须要一个跨进程的通讯机制来实现数据传递,在 Android 显示系统中,使用了 Android 的匿名共享内存:SharedClient,每个应用和 SurfaceFlinger 之间都会建立一个SharedClient ,而后在每一个 SharedClient 中,最多能够建立 31 个 SharedBufferStack,每一个 Surface 都对应一个 SharedBufferStack,也就是一个 Window。

一个 SharedClient 对应一个Android 应用程序,而一个 Android 应用程序可能包含多个窗口,即 Surface 。也就是说 SharedClient 包含的是 SharedBufferStack的集合,其中在显示刷新机制中用到了双缓冲和三重缓冲技术。最后总结起来显示总体流程分为三个模块:应用层绘制到缓存区,SurfaceFlinger 把缓存区数据渲染到屏幕,因为是不一样的进程,因此使用 Android 的匿名共享内存 SharedClient 缓存须要显示的数据来达到目的。

除此以外,咱们还须要一个名词:FPS。FPS 表示每秒传递的帧数。在理想状况下,60 FPS 就感受不到卡,这意味着每一个绘制时长应该在16 ms 之内。可是 Android 系统颇有可能没法及时完成那些复杂的页面渲染操做。Android 系统每隔 16ms 发出 VSYNC 信号,触发对 UI 进行渲染,若是每次渲染都成功,这样就可以达到流畅的画面所需的 60FPS。若是某个操做花费的时间是 24ms ,系统在获得 VSYNC 信号时就没法正常进行正常渲染,这样就发生了丢帧现象。那么用户在 32ms 内看到的会是同一帧画面,这种现象在执行动画或滑动列表比较常见,还有多是你的 Layout 太过复杂,层叠太多的绘制单元,没法在 16ms 完成渲染,最终引发刷新不及时。

卡顿根本缘由

根据Android 系统显示原理能够看到,影响绘制的根本缘由有如下两个方面:

  • 绘制任务过重,绘制一帧内容耗时太长。
  • 主线程太忙,根据系统传递过来的 VSYNC 信号来时还没准备好数据致使丢帧。

绘制耗时太长,有一些工具能够帮助咱们定位问题。主线程太忙则须要注意了,主线程关键职责是处理用户交互,在屏幕上绘制像素,并进行加载显示相关的数据,因此特别须要避免任何主线程的事情,这样应用程序才能保持对用户操做的即时响应。总结起来,主线程主要作如下几个方面工做:

  • UI 生命周期控制
  • 系统事件处理
  • 消息处理
  • 界面布局
  • 界面绘制
  • 界面刷新

除此以外,应该尽可能避免将其余处理放在主线程中,特别复杂的数据计算和网络请求等。

性能分析工具

性能问题并不容易复现,也很差定位,可是真的碰到问题仍是须要去解决的,那么分析问题和确认问题是否解决,就须要借助相应的的调试工具,好比查看 Layout 层次的 Hierarchy View、Android 系统上带的 GPU Profile 工具和静态代码检查工具 Lint 等,这些工具对性能优化起到很是重要的做用,因此要熟悉,知道在什么场景用什么工具来分析。

1,Profile GPU Rendering

在手机开发者模式下,有一个卡顿检测工具叫作:Profile GPU Rendering,如图:

Profile GPU Rendering

它的功能特色以下:

  • 一个图形监测工具,能实时反应当前绘制的耗时
  • 横轴表示时间,纵轴表示每一帧的耗时
  • 随着时间推移,从左到右的刷新呈现
  • 提供一个标准的耗时,若是高于标准耗时,就表示当前这一帧丢失

2,TraceView

TraceView 是 Android SDK 自带的工具,用来分析函数调用过程,能够对 Android 的应用程序以及 Framework 层的代码进行性能分析。它是一个图形化的工具,最终会产生一个图表,用于对性能分析进行说明,能够分析到每个方法的执行时间,其中能够统计出该方法调用次数和递归次数,实际时长等参数维度,使用很是直观,分析性能很是方便。

3,Systrace UI 性能分析

Systrace 是 Android 4.1及以上版本提供的性能数据采样和分析工具,它是经过系统的角度来返回一些信息。它能够帮助开发者收集 Android 关键子系统,如 surfaceflinger、WindowManagerService 等 Framework 部分关键模块、服务、View系统等运行信息,从而帮助开发者更直观地分析系统瓶颈,改进性能。Systrace 的功能包括跟踪系统的 I/O 操做、内核工做队列、CPU 负载等,在 UI 显示性能分析上提供很好的数据,特别是在动画播放不流畅、渲染卡等问题上。

优化建议

1,布局优化

布局是否合理主要影响的是页面测量时间的多少,咱们知道一个页面的显示测量和绘制过程都是经过递归来完成的,多叉树遍历的时间与树的高度h有关,其时间复杂度 O(h),若是层级太深,每增长一层则会增长更多的页面显示时间,因此布局的合理性就显得很重要。

那布局优化有哪些方法呢,主要经过减小层级、减小测量和绘制时间、提升复用性三个方面入手。总结以下:

  • 减小层级。合理使用 RelativeLayout 和 LinerLayout,合理使用Merge。
  • 提升显示速度。使用 ViewStub,它是一个看不见的、不占布局位置、占用资源很是小的视图对象。
  • 布局复用。能够经过 标签来提升复用。
  • 尽量少用wrap_content。wrap_content 会增长布局 measure 时计算成本,在已知宽高为固定值时,不用wrap_content 。
  • 删除控件中无用的属性。

2,避免过分绘制

过分绘制是指在屏幕上的某个像素在同一帧的时间内被绘制了屡次。在多层次重叠的 UI 结构中,若是不可见的 UI 也在作绘制的操做,就会致使某些像素区域被绘制了屡次,从而浪费了多余的 CPU 以及 GPU 资源。

如何避免过分绘制呢,以下:

  • 布局上的优化。移除 XML 中非必须的背景,移除 Window 默认的背景、按需显示占位背景图片
  • 自定义View优化。使用 canvas.clipRect()来帮助系统识别那些可见的区域,只有在这个区域内才会被绘制。

3,启动优化

经过对启动速度的监控,发现影响启动速度的问题所在,优化启动逻辑,提升应用的启动速度。启动主要完成三件事:UI 布局、绘制和数据准备。所以启动速度优化就是须要优化这三个过程:

  • UI 布局。应用通常都有闪屏页,优化闪屏页的 UI 布局,能够经过 Profile GPU Rendering 检测丢帧状况。
  • 启动加载逻辑优化。能够采用分布加载、异步加载、延期加载策略来提升应用启动速度。
  • 数据准备。数据初始化分析,加载数据能够考虑用线程初始化等策略。

4,合理的刷新机制

在应用开发过程当中,由于数据的变化,须要刷新页面来展现新的数据,但频繁刷新会增长资源开销,而且可能致使卡顿发生,所以,须要一个合理的刷新机制来提升总体的 UI 流畅度。合理的刷新须要注意如下几点:

  • 尽可能减小刷新次数。
  • 尽可能避免后台有高的 CPU 线程运行。
  • 缩小刷新区域。

5,其余

在实现动画效果时,须要根据不一样场景选择合适的动画框架来实现。有些状况下,能够用硬件加速方式来提供流畅度。

内存优化

在 Android 系统中有个垃圾内存回收机制,在虚拟机层自动分配和释放内存,所以不须要在代码中分配和释放某一块内存,从应用层面上不容易出现内存泄漏和内存溢出等问题,可是须要内存管理。Android 系统在内存管理上有一个 Generational Heap Memory 模型,内存回收的大部分压力不须要应用层关心, Generational Heap Memory 有本身一套管理机制,当内存达到一个阈值时,系统会根据不一样的规则自动释放系统认为能够释放的内存,也正是由于 Android 程序把内存控制的权力交给了 Generational Heap Memory,一旦出现内存泄漏和溢出方面的问题,排查错误将会成为一项异常艰难的工做。除此以外,部分 Android 应用开发人员在开发过程当中并无特别关注内存的合理使用,也没有在内存方面作太多的优化,当应用程序同时运行愈来愈多的任务,加上愈来愈复杂的业务需求时,彻底依赖 Android 的内存管理机制就会致使一系列性能问题逐渐呈现,对应用的稳定性和性能带来不可忽视的影响,所以,解决内存问题和合理优化内存是很是有必要的。

Android内存管理机制

Android 应用都是在 Android 的虚拟机上运行,应用 程序的内存分配与垃圾回收都是由虚拟机完成的。在 Android 系统,虚拟机有两种运行模式:Dalvik 和 ART。

1,Java对象生命周期

Java对象生命周期

通常Java对象在虚拟机上有7个运行阶段:

建立阶段->应用阶段->不可见阶段->不可达阶段->收集阶段->终结阶段->对象空间从新分配阶段

2,内存分配

在 Android 系统中,内存分配其实是对堆的分配和释放。当一个 Android 程序启动,应用进程都是从一个叫作 Zygote 的进程衍生出来,系统启动 Zygote 进程后,为了启动一个新的应用程序进程,系统会衍生 Zygote 进程生成一个新的进程,而后在新的进程中加载并运行应用程序的代码。其中,大多数的 RAM pages 被用来分配给Framework 代码,同时促使 RAM 资源可以在应用全部进程之间共享。

可是为了整个系统的内存控制须要,Android 系统会为每个应用程序都设置一个硬性的 Dalvik Heap Size 最大限制阈值,整个阈值在不一样设备上会由于 RAM 大小不一样而有所差别。若是应用占用内存空间已经接近整个阈值时,再尝试分配内存的话,就很容易引发内存溢出的错误。

3,内存回收机制

咱们须要知道的是,在 Java 中内存被分为三个区域:Young Generation(年轻代)、Old Generation(年老代)、Permanent Generation(持久代)。最近分配的对象会存放在 Young Generation 区域。对象在某个时机触发 GC 回收垃圾,而没有回收的就根据不一样规则,有可能被移动到 Old Generation,最后累积必定时间在移动到 Permanent Generation 区域。系统会根据内存中不一样的内存数据类型分别执行不一样的 GC 操做。GC 经过肯定对象是否被活动对象引用来肯定是否收集对象,进而动态回收无任何引用的对象占据的内存空间。但须要注意的是频繁的 GC 会增长应用的卡顿状况,影响应用的流畅性,所以须要尽可能减小系统 GC 行为,以便提升应用的流畅度,减少卡顿发生的几率。

内存分析工具

作内存优化前,须要了解当前应用的内存使用现状,经过现状去分析哪些数据类型有问题,各类类型的分布状况如何,以及在发现问题后如何发现是哪些具体对象致使的,这就须要相关工具来帮助咱们。

1,Memory Monitor

Memory Monitor 是一款使用很是简单的图形化工具,能够很好地监控系统或应用的内存使用状况,主要有如下功能:

  • 显示可用和已用内存,而且以时间为维度实时反应内存分配和回收状况。
  • 快速判断应用程序的运行缓慢是否因为过分的内存回收致使。
  • 快速判断应用是否因为内存不足致使程序崩溃。

2,Heap Viewer

Heap Viewer 的主要功能是查看不一样数据类型在内存中的使用状况,能够看到当前进程中的 Heap Size 的状况,分别有哪些类型的数据,以及各类类型数据占比状况。经过分析这些数据来找到大的内存对象,再进一步分析这些大对象,进而经过优化减小内存开销,也能够经过数据的变化发现内存泄漏。

3,Allocation Tracker

Memory Monitor 和 Heap Viewer 均可以很直观且实时地监控内存使用状况,还能发现内存问题,但发现内存问题后不能再进一步找到缘由,或者发现一块异常内存,但不能区别是否正常,同时在发现问题后,也不能定位到具体的类和方法。这时就须要使用另外一个内存分析工具 Allocation Tracker,进行更详细的分析, Allocation Tracker 能够分配跟踪记录应用程序的内存分配,并列出了它们的调用堆栈,能够查看全部对象内存分配的周期。

4,Memory Analyzer Tool(MAT)

MAT 是一个快速,功能丰富的 Java Heap 分析工具,经过分析 Java 进程的内存快照 HPROF 分析,从众多的对象中分析,快速计算出在内存中对象占用的大小,查看哪些对象不能被垃圾收集器回收,并能够经过视图直观地查看可能形成这种结果的对象。

常见内存泄漏场景

若是在内存泄漏发生后再去找缘由并修复会增长开发的成本,最好在编写代码时就可以很好地考虑内存问题,写出更高质量的代码,这里列出一些常见的内存泄漏场景,在之后的开发过程当中须要避免这类问题。

  • 资源性对象未关闭。好比Cursor、File文件等,每每都用了一些缓冲,在不使用时,应该及时关闭它们。
  • 注册对象未注销。好比事件注册后未注销,会致使观察者列表中维持着对象的引用。
  • 类的静态变量持有大数据对象。
  • 非静态内部类的静态实例。
  • Handler临时性内存泄漏。若是Handler是非静态的,容易致使 Activity 或 Service 不会被回收。
  • 容器中的对象没清理形成的内存泄漏。
  • WebView。WebView 存在着内存泄漏的问题,在应用中只要使用一次 WebView,内存就不会被释放掉。

除此以外,内存泄漏可监控,常见的就是用LeakCanary 第三方库,这是一个检测内存泄漏的开源库,使用很是简单,能够在发生内存泄漏时告警,而且生成 leak tarce 分析泄漏位置,同时能够提供 Dump 文件进行分析。

优化内存空间

没有内存泄漏,并不意味着内存就不须要优化,在移动设备上,因为物理设备的存储空间有限,Android 系统对每一个应用进程也都分配了有限的堆内存,所以使用最小内存对象或者资源能够减少内存开销,同时让GC 能更高效地回收再也不须要使用的对象,让应用堆内存保持充足的可用内存,使应用更稳定高效地运行。常见作法以下:

  • 对象引用。强引用、软引用、弱引用、虚引用四种引用类型,根据业务需求合理使用不一样,选择不一样的引用类型。
  • 减小没必要要的内存开销。注意自动装箱,增长内存复用,好比有效利用系统自带的资源、视图复用、对象池、Bitmap对象的复用。
  • 使用最优的数据类型。好比针对数据类容器结构,可使用ArrayMap数据结构,避免使用枚举类型,使用缓存Lrucache等等。
  • 图片内存优化。能够设置位图规格,根据采样因子作压缩,用一些图片缓存方式对图片进行管理等等。

稳定性优化

Android 应用的稳定性定义很宽泛,影响稳定性的缘由不少,好比内存使用不合理、代码异常场景考虑不周全、代码逻辑不合理等,都会对应用的稳定性形成影响。其中最多见的两个场景是:Crash 和 ANR,这两个错误将会使得程序没法使用,比较经常使用的解决方式以下:

  • 提升代码质量。好比开发期间的代码审核,看些代码设计逻辑,业务合理性等。
  • 代码静态扫描工具。常见工具备Android Lint、Findbugs、Checkstyle、PMD等等。
  • Crash监控。把一些崩溃的信息,异常信息及时地记录下来,以便后续分析解决。
  • Crash上传机制。在Crash后,尽可能先保存日志到本地,而后等下一次网络正常时再上传日志信息。

耗电优化

在移动设备中,电池的重要性不言而喻,没有电什么都干不成。对于操做系统和设备开发商来讲,耗电优化一致没有中止,去追求更长的待机时间,而对于一款应用来讲,并非能够忽略电量使用问题,特别是那些被归为“电池杀手”的应用,最终的结果是被卸载。所以,应用开发者在实现需求的同时,须要尽可能减小电量的消耗。

在 Android5.0 之前,在应用中测试电量消耗比较麻烦,也不许确,5.0 以后专门引入了一个获取设备上电量消耗信息的 API:Battery Historian。Battery Historian 是一款由 Google 提供的 Android 系统电量分析工具,和Systrace 同样,是一款图形化数据分析工具,直观地展现出手机的电量消耗过程,经过输入电量分析文件,显示消耗状况,最后提供一些可供参考电量优化的方法。

除此以外,还有一些经常使用方案可提供:

  • 计算优化,避开浮点运算等。
  • 避免 WaleLock 使用不当。
  • 使用 Job Scheduler。

安装包大小优化

应用安装包大小对应用使用没有影响,但应用的安装包越大,用户下载的门槛越高,特别是在移动网络状况下,用户在下载应用时,对安装包大小的要求更高,所以,减少安装包大小可让更多用户愿意下载和体验产品。

经常使用应用安装包的构成,如图所示:

应用安装包构成

从图中咱们能够看到:

  • assets文件夹。存放一些配置文件、资源文件,assets不会自动生成对应的 ID,而是经过 AssetManager 类的接口获取。

  • res。res 是 resource 的缩写,这个目录存放资源文件,会自动生成对应的 ID 并映射到 .R 文件中,访问直接使用资源 ID。

  • META-INF。保存应用的签名信息,签名信息能够验证 APK 文件的完整性。

  • AndroidManifest.xml。这个文件用来描述 Android 应用的配置信息,一些组件的注册信息、可以使用权限等。

  • classes.dex。Dalvik 字节码程序,让 Dalvik 虚拟机可执行,通常状况下,Android 应用在打包时经过 Android SDK 中的 dx 工具将 Java 字节码转换为 Dalvik 字节码。

  • resources.arsc。记录着资源文件和资源 ID 之间的映射关系,用来根据资源 ID 寻找资源。

减小安装包大小的经常使用方案

  • 代码混淆。使用proGuard 代码混淆器工具,它包括压缩、优化、混淆等功能。
  • 资源优化。好比使用 Android Lint 删除冗余资源,资源文件最少化等。
  • 图片优化。好比利用 AAPT 工具对 PNG 格式的图片作压缩处理,下降图片色彩位数等。
  • 避免重复功能的库,使用 WebP图片格式等。
  • 插件化。好比功能模块放在服务器上,按需下载,能够减小安装包大小。

小结

性能优化不是更新一两个版本就能够解决的,是持续性的需求,持续集成迭代反馈。在实际的项目中,在项目刚开始的时候,因为人力和项目完成时间限制,性能优化的优先级比较低,等进入项目投入使用阶段,就须要把优先级提升,但在项目初期,在设计架构方案时,性能优化的点也须要提前考虑进去,这就体现出一个程序员的技术功底了。

何时开始有性能优化的需求,每每都是从发现问题开始,而后分析问题缘由及背景,进而寻找最优解决方案,最终解决问题,这也是平常工做中常会用到的处理方式。

相关文章
相关标签/搜索