公司的新需求终于解决完了,离测试和发布还有段时间,第一次体验了下没需求没bug的感觉,真是舒爽~然后翻了翻有什么可以学的。无意翻到了Android后期发展的五大趋势。一、性能优化。二、高级UI。三、JNI/NDK开发。四、架构师。五、RN开发。这也许将会是我的进阶趋势。早已知道在瓶颈期的我,似乎看到了突破的希望的。

其实,关注我的或者在群里的小伙伴也知道,UI那块我问题不大。但是高级UI就有难度了。我们先不管他,一个一个来。先从性能优化来。其实我是拒绝写这篇文章的。为什么?性能优化的分类很多,一个分类写一篇感觉篇幅量很小,结合在一起写有感觉很大。而我目前打算整体的整理一下。

那么我们先分析下性能优化有哪几个方面:一、内存优化。二、UI优化(布局优化和绘制优化)。三、速度的优化(线程优化/网路优化)。四、电量优化。五、启动优化。应该就这些了。那么这只是五大方面,里面还结合了各种细节方面的。不急,我们下面一个个的介绍。

内存优化

关于性能优化我们可以不知道其他的,但一定要知道内存优化。因为内存泄漏可以Android的常客。那么什么是内存泄漏呢?内存不在GC的掌控范围之内了。那么java的GC内存回收机制是什么?某对象不再

有任何引用的时候才会进行回收。那么GC回收机制的原理是什么?又或者说可以作为GC Root引用点的是啥?或许有人听不懂我在讲啥。我们先来看张图。

当我们向上寻找,一直寻找到GC Root的时候,此对象不会进行回收,例如,一个Activity。那么如果我们向上寻找,直到找到GC Root对象的时候,就说明它是不可以回收的,例如,我定义了一个int a;但是这个数据,我整个页面或者说整个项目都没有用到,则这个对象会被GC掉。

GC的引用点

1. java栈中引用的对象
2. 方法静态引用的对象
3. 方法常量引用的对象
4. Native中JNI引用的对象
5. Thread——「活著的」线程

如何判断

那么我们如何判断一个对象是一个垃圾对象,可以讲他进行回收呢?举了小例子教你们如何区分:

一般在学校吃饭,我们有两种情况,第一:吃完饭就直接走人,碗筷留给阿姨来收拾处理。
第二:吃完之后把碗筷放到收盘处直接进行回收。
但我们是个有素质的人,一般采用第二种情况,但根据想法,我们更倾向于第一种。
那么一般在饭店或者KFC中,都是第一种情况。
那么此时,问题来了,如果我已经吃完饭,然后我并没有离开饭店,做在位置上和朋友吹吹牛逼,谈谈理想,聊聊人生。
那么桌上那一堆碗筷是收还是不收?讲道理是不能收的。虽然实际也是不能收的。因为顾客是上帝~~~

So,我们如何判断一个对象是一个可回收的垃圾对象呢?这是我们的一个主观的判断。但是有种情况我们是必须要考虑到的,没错,就是内存过多无法释放的时候,会直接导致OOM。整个项目boom炸了。什么鬼?outofmemory。没错就是它。

内存溢出

分析原因

我们需要分析内存溢出的原因,我们先来看一张图:

内存泄漏一般导致应用卡顿,极端情况会导致项目boom。Boom的原因是因为超过内存的阈值。

原因主要有两方面:

  • 代码存在泄漏,内存无法及时释放导致oom(这个我们后面说)
  • 一些逻辑消耗了大量内存,无法及时释放或者超过导致oom

所谓消耗大量的内存的,绝大多数是因为图片载入。这是我们oom出现最频繁的地方。我前面有写过图片载入的方法,一个是控制每次载入的数量,第二,保证每次滑动的时候不进行载入,滑动完进行载入。一般情况使用先进后出,而不是先进先出。不过一般我们图片载入都是使用fresco或者Glide等开源库。

我们来看下下面两张图:

对比两张图,我们可以在第一张的情况出现了oom情况,我们通过log列印发现,处理的好像没什么问题,换句话说,如果我不放那0.8M的图片。然后继续不停的操作同样会出现OOM,然而我们就蒙了。没什么图片载入怎么就这么崩掉了。

如何查看

首先,我们确定我们项目或者某几个类里面是否存在内存溢出的问题。我们可以通过如下方法:

  • Android–>System Information–>MemoryUsage查看Object里面是否有没有被释放的Views和Activity
  • 命令行模式:adb shell dumpsys meminfo 包名 -d

就那我公司的项目举例把。首先,我们在这边可以看到memory。CPU和net的使用情况。

我们找到Object。看看我们内存的消耗情况。

随便这么一看,尼玛蛋,1300左右的view和一个Activity。还有3个context。可怕。。可以理解为一个Activity里面使用了将近1300个view。。。想都不敢想。。。

我们可以通过看Memory Monitor工具。 检查一个一个的动作。(比如Activity的跳转)。反复多次执行某一个操作,不断的通过这个工具查看内存的大概变化情况。 前后两个内存变化增加了不少。

我们可以更仔细的查找泄漏的位置,在AS里面使用 Heap SnapShot工具(堆栈快照)。如图所示:

我们点击后,他会进行一段时间的监控,然后会生成一个文件。我们点击我们package tree view。

我们找到自己项目的包名。然后进行进一步的分析。首先看一下2个列表的列名到底指的什么。

实例化对象的详细信息:

我们来随便的看一下内存中的数量:

这还是我们刚进手机,一个bean就被调用了这么多次。简直可怕。这个我们可以通过内存分析工具解决的。

内存分析工具

性能优化工具:

  • Heap SnapShot工具
  • Heap Viewer工具
  • LeakCanary工具
  • MAT工具
  • TraceView工具(Device Monitor)

第三方分析工具:

  • MemoryAnalyzer
  • GT Home
  • iTest

因为我没有这些工具,无法进行演示。

注意事项

  • 我们尽量不要使用Activity的上下文,而是使用application的上下文,因为application的生命周期长,进程退出时才会被销毁。所以,单例模式是最容易造成内存溢出的原本所在,因为单例模式的生命周期的应该和application的生命周期一样长,而不是和Activity的相同。
  • Animation也会导致内存溢出,为什么?因为我们是通过view来进行演示的,导致view被Activity持有,而Activity又持有view。最后因为Activity无法释放,导致内存泄漏。解决方法是在Activity的ondestory()方法中调用Animation.cancle()进行停止,当然一些简单的动画我们可以通过自定义view来解决。至少我现在已经很少使用Animation了。没有一个动画是自定义view解决不了的。如何有,那就是两个

今天写到这突然有急事,各位不好意思,明天更完剩下的

私信回复「资料」获取高级UI、Gradle、RxJava、小程序、Hybrid、移动架构、React Native、性能优化等技术教程!架构师课程、NDK、混合式开发全方 面的 Android高级实践技术讲解性能优化架构思维导图,和BATJ面试题及答案。

推荐阅读:

相关文章