当前位置: 首页>大数据>正文

程序员自我修养之性能优化篇

一、卡顿优化

程序员自我修养之性能优化篇,第1张

1、UI优化方式 :?

布局复杂、层级过深、自定义view防止过度绘制、ViewStub的方式去占位布局

2、冷启动优化方式 :

?异步(IntentService)、懒加载(Handler处理)、延迟(IdleHandler,cpu空闲时间加载数据)

3、响应优化方式 :?

滑动过程中不加载数据、预加载、懒加载

4.绘制界面分为两个步骤:

? ? ? ? 加载布局、图像绘制

5.统计启动时间的方法:

? ? ? ? a. TraceCompat.beginSection();

? ? ? ? ? ? TraceCompat.endSection();?

? ??????wall time : 是代码执行完花费的时间(包含cpu和IO的读写操作)

  cpu time : 是cpu花费多少时间执行完这段代码(这里才是作为主要的优化时间点)

? ? ? ? 执行systrace.py这个参数,就可以把你加的日志生成一个html文件进行查看,它也可以底层的执行时间

? ? ? ? b.? 使用AOP切面编程:代码无侵略性

? ? ? ? c.? AS的profiler这个工具也可以查看耗时

?6.UI常见问题以及优化

? ? ? ? 常见问题 : 过度绘制、布局复杂、层级过深

? ? ? ? 解决办法:? 减少从xml文件创建为对象、减少过度绘制操作

? ? ? ? 1).xml文件上解决过度绘制 : 使用android:backgroud会增加一次过度绘制次数

? ? ? ? 2).自定义view过度绘制:

clipRect : 识别可见区域绘制,非可见部分就不进行绘制,俗称裁剪。注意:在调用cilpRect、scale(旋转)、translate(平移)、缩放等这些操作之前,需要调用canvas.save方法

? ? ? ? 3).可以采用ViewStub的方式去占位布局,使用时再去渲染

4).查看代码性能问题:AS->Analyze->Inspect Code?查看关键字Performance、Xml文件

? ? ? ? 5).常见的异步操作的手段

?AsyncTask :UI线程和工作线程之间快速切换提供的简单机制

? ? ? ? ?适用场景:立即需要启动,但是异步执行的生命周期短暂

HanderThread :?为某些回调方法或者等待某些任务执行设置一个专属线程

ThreadPool :?把任务分解到各个不同的线程上,进行同时并发处理

IntentService :?适合执行由UI触发的后台service,可以把后台执行任务反馈给UI(适合在Application 的onCrate里面适用,操作简单,且自己可以销毁对象,其他方式小题大做)

? ? ? ?6).ListView性能优化

? ? ? ? ????a.复用converView

? ? ? ? ????b.复用viewHolder

? ? ? ? ????c.getView少做耗时的操作

? ? ? ? ????d.滑动停止时候再去加载图片

? ? ? ? ? ? e.使用异步线程加载图片

滑动时候为什么不会发生OOM的原因(RecycleBin的复用机制)

? ? ? ? ?RecycleBin里面有两个存数据的数组,一个是ActivtyView数组,这个是给用户展示的view,另一个是ScrapView数组,它是不需要展示view,但是已经创建,为了二次展示作为复用来使用。展示的view会先从ScrapView数组去遍历查找是否存在,如果存在直接在复用给ActivityView来使用,如果不存在创建之后给ActivityView来展示。

?7.Systrace去检查UI卡顿问题

? ? 在android-sdk/platform-tools/systrace/执行systrace.py

? ? 执行python systrace.py --time=10 -o mynewtrace.html 命令生成.html文件

W:界面放大

S:界面缩小

A:界面左移

D:界面右移

程序员自我修养之性能优化篇,第2张
程序员自我修养之性能优化篇,第3张

二、内存优化

? ? 1.OOM容易混淆的概念

? ??????内存溢出:我们申请的内存已经超出虚拟机的最大内存的限度就会抛出Out? Of? memory

????????内存抖动 :? 短时间大量的对象被创建然后就释放,触发的GC机制,严重占用内存区。

????????内存泄露 :? 我们要回收的对象无法进行GC的回收操作

? ? ? ? 造成OOM的原因:

? ? ? ? Java堆内存溢出、无足够的连续空间、虚拟内存不足、线程数量超出限制

? ? 2.内存泄漏的常见案例

????????1).单例:长生命周期的对象(Application的对象)被短生命周期的对象持有

2). handler :?非静态内部类持有外部类的引用,导致于无法释放外部类的对象---->解决方法将handler至于为static的对象,然后将外部类改为弱引用来使用

? ? ? ? 3).线程引起: AsyncTask和Runnable使用匿名内部类,因为非静态内部类持有外部类的引用,和handler类似

? ? ? ? 4).文件的读写、数据库网络启用后没有关闭、三方的框架没有销毁

? ? ? ? 5).注册广播以及使用三方的库没有再销毁时候关闭

? ? ?3.不同内存的类型

程序员自我修养之性能优化篇,第4张

? ??内存的类别如下:

????????Java:从 Java 或 Kotlin 代码分配的对象的内存。

????????Native:从 C 或 C++ 代码分配的对象的内存。

????????Graphics:图形缓冲区队列向屏幕显示像素(包括 GL 表面、GL 纹理等等)所使用的内存。

? ? ????Stack:您的应用中的原生堆栈和 Java 堆栈使用的内存

????????Code:您的应用用于处理代码和资源(如 dex 字节码、经过优化或编译的 dex 代码、.so 库和字体)的内存。

????????Others:您的应用使用的系统不确定如何分类的内存。

?4.内存优化方向

?????1).BitMap的图片优化,避免滥用Bitmap导致内存的浪费,使用完及时回收

? ? ?2).减少对象重复创建,多采用复用方式,避免内存碎片化

? ? ?3).包体的优化 :?混淆、删除多余文件和图片、压缩图片、语言和cpu架构的配置

? ? ?4).使用适当的数据结构去存储数据

?5.内存优化之垃圾对象的处理

程序员自我修养之性能优化篇,第5张

?FinalizerReference就会越来越大原因:

一旦用户创建对象(重写了finalize函数)的速度快于finalize队列移除各元素的速度,finalize里面回收的是弱引用和虚引用,虚引用主要记录对象的销毁,也因为JVM的垃圾回收、内存管理都是守护线程,他们优先级比用户线程低很多。设置守护线程方法是setDaemon(true)的方法

解决FinalizerReference过大的办法:

????1.不要重写finalize()方法,实在要释放资源,到destroy一类函数中处理

????2.重复利用资源,可以采用对象池方式处理,防止发生内存抖动,避免反复创建

????3.调用System.runFinalization()回收

?System.gc()和System.runFinalization()区别:

? ? System.gc():告诉垃圾收集器打算进行垃圾收集,而垃圾收集器进不进行收集是不确定的

? ? System.runFinalization():强制调用已经失去引用的对象的finalize方法

?6.内存优化之碎片化?

程序员自我修养之性能优化篇,第6张

?Linux内存管理:(做为了解,后续再补充)

? ? 优质的网址:https://www.kancloud.cn/zhangyi8928/kernel/531016

VSS?: 虚拟内存,预计要占用的内存但并没有实际占用。

RSS?: 一个进程在RAM中实际使用内存。该进程独享内存(USS)+共享内存

PSS :??一个进程的PSS=USS+该进程所占共享内存。所有进程的PSS相加即为系统占用内存总和。

USS?: 一个进程独享的内存。该进程被杀死后USS会被系统回收

? ??解决方式:

? ?共享元设计模式对象池去处理?: 创建一个读对象之后就不会再创建了,只是里面的数据会被清空,对象不会被销毁

? ? 对象池线程不安全的

????Pools.SimplePool<Integer> pool = new Pools.SimplePool(10);

? ? 对象池线程安全的

? ? Pools.SynchronizedPool<Integer> pool1 = new Pools.SynchronizedPool<>(10);? ??

?java内存的大小计算 :?shallow size、retained size

? ??shallow size : 自身占用的内存的大小

? ??retained size :该对象能直接或间接访问到对象的shallow size之和

? ?案例讲解:

程序员自我修养之性能优化篇,第7张

从obj1入手,上图中蓝色节点代表仅仅只有通过obj1才能直接或间接访问的对象。因为可以通过GC Roots访问,所以左图的obj3不是蓝色节点;而在右图却是蓝色,因为它已经被包含在retained集合内。

? ? 对于左图,obj1的retained size是obj1、obj2、obj4的shallow size总和;右图的retained size是obj1、obj2、obj3、obj4的shallow size总和。

????对于obj2,它的retained size是:在左图中,是obj2和obj4的shallow size的和;在右图中,是obj2、obj3和obj4的shallow size的和。

?7.内存优化之图片优化

? ? ?1). 一张图片加载到内存的计算

? ? ? ? 加载分辨率为1080*452的图片,文件本身大小是56kb

? ? ? ? 1080*452*4B =? 1952640B -----> 1.86MB? 这样计算会有问题

? ? ? ? 正确计算方式:

程序员自我修养之性能优化篇,第8张

??????1080*452*4B*(设备的dpi(240)/目录的dpi(1.5))-------->这个就可以被放在对应目录下的正确的大小

? ? 2).BitMap的几种像素格式

????????ALPHA_8:每个像素都需要1(8位)个字节的内存,只存储位图的透明度,没有颜色信息

????????ARGB_4444:A(Alpha)占4位的精度,R(Red)占4位的精度,G(Green)占4位的精度,B(Blue)占4位的精度,加起来一共是16位的精度,折合是2个字节,也就是一个像素占两个字节的内存,同时存储位图的透明度和颜色信息。不过由于该精度的位图质量较差,官方不推荐使用

????????ARGB_8888:这个类型的跟ARGB_4444的原理是一样的,只是A,R,G,B各占8个位的精度,所以一个像素占4个字节的内存。由于该类型的位图质量较好,官方特别推荐使用。但是,如果一个480*800的位图设置了此类型,那个它占用的内存空间是:480*800*4/(1024*1024)=1.5M

????????RGB_565:同理,R占5位精度,G占6位精度,B占5位精度,一共是16位精度,折合两个字节。这里注意的时,这个类型存储的只是颜色信息,没有透明度信息

? ??3).图片优化的方式 : 降低分辨率、减少每个像素点大小

? ??????如何去加载一个大图的方式:根本原因是降低图片的像素

????????图片的优化行为:

? ??????质量压缩 :? 可以降低图片质量,不能降低图片的像素,不能起到图片优化效果

????????采样率压缩 :? 可以降低图片的像素options.inSample 这个参数,起到图片优化效果

? ? ? ? 尺寸压缩 : 通过压缩图片宽、高来降低图片的像素,起到图片优化效果

? ? ? ? 改变图片的格式,从RGBA_8888(默认)转变为其他格式,这种不推荐使用

? ?4).? 图像的开辟和销毁

? ??????图像开辟:

? ??????图片需要缩放,都是开辟在native层的,如果不需要缩放,8.0以前是在java层开辟的

? ??????8.0以下放在 java的内存之中

? ??????8.0以上是放在native内存之中,有2G内存供使用

? ??????图片销毁:

? ??????bitMap.recycle() : 回收是像素数据,只是在8.0以及以上可以使用

? ? ? ? 6.0以上是通过监听GC触发机制去传递给底层使用,然后进行销毁,监听方式是ReferenceQueue队列去监听

? ? ?5).BitMap的BitmapFactory.Options参数讲解

? ??????Scale(转换率) =? inTargetDensity /? inDensity

????????BitmapFactory.Options options =new BitmapFactory.Options();

? ? ? ? //会根据drawable文件夹的分辨率来赋值

????????options.inDensity

? ? ? ? //会根据屏幕的像素密度来赋值

????????options.inTargetDensity

? ??????//对图片进行压缩,对图片宽和高各压缩2倍

????????options.inSampleSize = 2

? ??????//设置图片是否会被压缩,它的参数就是由Scale(转换率)去计算

????????options.inScaled? ? ? ? ? ? ? ? ?

? ??????//为true不会得到bitMap的对象,而是可以的高宽、高的信息

????????options.inJustDecodeBounds

? ??????//代表资源图片的的宽

????????options.outWidth;

? ??????//代表资源图片的的高

????????options.outHeight

? ??????//代表BitMap可以复用

????????options.inMutable

? ??????//设置图片

????????options.inBitmap

????Bitmap bitmap = BitmapFactory.decodeResource(getResources(),? ? ? ? ? ? ? ? ????R.drawable.ic_launcher_background, options);

? 8.内存优化之检测系统接口

? ??OnLowMemory:在系统内存不足,所有后台程序(优先级为background的进程,不是指后台运行的进程)都被杀死时,系统会调用OnLowMemory

????OnTrimMemory:系统会根据不同的内存状态来回调。系统提供的回调有:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Application/Activity/Fragement/Service/ContentProvider? ? ??

? ??TRIM_MEMORY_COMPLETE:内存不足,并且该进程在后台进程列表最后一个,马上就要被清理

????TRIM_MEMORY_MODERATE:内存不足,并且该进程在后台进程列表的中部。

????TRIM_MEMORY_BACKGROUND:内存不足,并且该进程是后台进程。

????TRIM_MEMORY_UI_HIDDEN:内存不足,并且该进程的UI已经不可见了。? ? ??

????TRIM_MEMORY_RUNNING_CRITICAL:内存不足(后台进程不足3个),并且该进程优先级比较高,需要清理内存

? ??TRIM_MEMORY_RUNNING_LOW:内存不足(后台进程不足5个),并且该进程优先级比较高,需要清理内存

????TRIM_MEMORY_RUNNING_MODERATE:内存不足(后台进程超过5个),并且该进程

OnLowMemory和OnTrimMemory的比较

? a.OnLowMemory被回调时,已经没有后台进程;而onTrimMemory被回调时,还有后台进程。

? b.OnLowMemory是在最后一个后台进程被杀时调用,一般情况是low memory killer 杀进程后触发;而OnTrimMemory的触发更频繁,每次计算进程优先级时,只要满足条件,都会触发。

? c.通过一键清理后,OnLowMemory不会被触发,而OnTrimMemory会被触发一次。

三、性能优化

冷启动优化方式:异步(IntentService)、懒加载(Handler处理)、延迟(IdleHandler,cpu空闲时间加载数据)

1.异步方式:

 ????a.Thread : 不容易复用,频繁创建及开销大

  b.HandlerThread : 自带消息循环,适用于长时间运行,不断从队列中获取任务

? ? ? ?c.IntentService :? 继承Service在内部创建一个HandlerThread ,异步,不占用主线程,优先级较高,不容易被系统kill

? ? ? ?d. AsyncTask : 无需处理线程切换,使用简单

? ? ? ? ????onPreExecute():异步任务开启之前回调,在主线程中执行

?  ????doInBackground():执行异步任务,在线程池中执行

   ????onProgressUpdate():在主线程中执行

   ????onPostExecute():在异步任务执行之后回调,在主线程中执行

  ? ????onCancelled():在异步任务被取消时回调

? ? ? ? ?e.线程池:容易复用,减少频繁创建、销毁时间,? 定时、任务队列、并发数控制

2.设置优先级

 Process.setThreadPriority() --------->这个可以设置优先级的高低

3.?采用IntentService启动。它是在异步线程中执行的,用完后它会自动释放对象的,它继承Serice也不容易被杀死。IntentService = Handler+HandlerThread,它的执行是有顺序的

4.BaseClassLoader里面有个Element的数组,里面就是所有的.dex的文件,它需要通过dexElement.findClass遍历整个数组,找到对应的.class才能启动,把我们要先启动的.class放在最前面,这样就可以加快启动速度。

5.SharedPreference的函数讲解

? ? ? ? 1).apply和commit的区别? ? ? ??

? ? ? ? ? ? apply是没有返回值的,在往磁盘写入时候,它是开启子线程不需要等待返回结果

? ? ? ? ? ? commit是会返回boolean的,主线程一直等往磁盘写入成功后,才会去执行

? ? ? ? 2).SharedPreference是存储在xml文件中,它线程安全性。

? ? ? ? ? ? 有缓存机制原因,高并发情况袭多进程是不安全安全

? ? ? ? 3).fileobserver多进程安全的原因

? ??????????startWatching和stopWatching里面都加了锁,并且锁的对象是修改的文件路径

四、ANR的产生和解决办法

?? ? 1、卡顿原理

? ? ? ? 产生原因:主线程做耗时操作就会产生卡顿,卡顿超过阈值,触发ANR。

卡顿产生因素:UI层级嵌套过深、Handler处理消息太耗时(barrier-->?msg.target == null,同步屏障消息)

? ? ? 2、卡顿监控

? ? ? ? ? 处理方式:Gradle Plugin+ASM,目前微信的Matrix 使用的卡顿监控方案就是字节码插桩

? ? ? ?3、ANR 原理

? ? ? ? ? ?1)、触发ANR的场景

? ??????????输入事件分发超时5s,包括按键和触摸事件

? ??????????比如前台广播在10s内未执行完成

? ? ? ? ? ? servive后台在20s内没有完成

? ? ? ? ? ?2)、servive、broadcast原理实现

? ? ? ? ? ? a)、Service的onCreate方法被调用时候调用mHandler.sendMessageDelayed发送延迟时间来处理事情

? ? ? ? ? ? b)、在任务完成前会调用 :mHandler.removeMessages把消息移除,这样剧不会产生ANR

? ? ? ? ? ? c)、任务没有前就会调用mAppErrors.appNotResponding,来告诉产生的原因,弹ANR Dialog

? ? ? ? ? ?3)、input原理实现

input来说即便某次事件执行时间超过timeout时长,只要用户后续在没有再生成输入事件,则不会触发ANR

? ? ? ?4、 ANR检测工具

? ????????一般来说有四种,分别为BlockCanay、ANR-WatchDog、SafeLooper和FileObserver

????????ANRWatchDog? ? ? ? ? ? ? ? ?

? ? ? ? ? ?原理: 开启一个子线程mThreadRunnable,每隔1s会执行一次mThreadRunnable,单独现场向主线程发送一个变量+1操作,休眠过后判断变量是否+1完成,如果未完成则警告

? ??????FileObserver

? ??????Android手机发生ANR后,会把信息存储在/data/anr/traces.txt文件,我们只需要监听这个文件的变化就可以知道是否发生了ANR。

五、APP瘦身优化

????1.删:删除无用的代码和资源

? ? 2.移:实在不行就抽离出,动态加载,动态下发。

? ? 3.压:压缩代码和资源

buildTypes {

? ? ? ? release {

? ? ? ? ? ? // 源代码混淆开启

? ? ? ? ? ? minifyEnabled true

? ? ? ? ? ? // 启动资源压缩

? ? ? ? ? ? shrinkResources true

? ? ? ? ? ? proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

? ? ? ? }

? ? }

? ? 4.? 图片优化 : 除了用PNG格式外,图片可以使用SVG(缩图),在gradle需要配置

? ??????defaultConfig {

........

// 使用support-v7兼容5.0以上

????????????vectorDrawables.useSupportLibrary = true

.........

? ? ????}

SVG官方介绍:https://developer.android.google.cn/studio/write/vector-asset-studio#about

? ? 5. 资源配置打包优化

defaultConfig {

????????????........

????????????// 只保留指定和默认资源

? ? ? ? ????resConfigs('zh-rCN', 'ko')

// 配置so库架构(真机:arm,模拟器:x86)

?abiFilters('armeabi',armeabi-v7a')

????????????.........

? ? ????}

-----------------------------下面以后还需要再好好总结-----------------------------------------------------

????RecycleView的优化之回收机制

程序员自我修养之性能优化篇,第9张

1.一级优化,优先优化item的列表,不需要重新绑定ViewHodler

? ? 里面有两个ArryList的链表,一个是mAttachScrap,另一个是mChangedScrap,当调用notifyItemChanged方法,通知有新的item时候,之前显示保存在mAttachScrap里面会直接复用ViewHolder,数据不需要重新绑定,新加入放在mChangedScrap里面再数据绑定

程序员自我修养之性能优化篇,第10张

2.二级和四级优化,Item列表优化缓存,mCacheView可以保存划出列表的item,调用setItemCacheSize方法可以确定缓存多少数据,超出这个数据会放在四级优化的recyclerPool这个缓存池里

程序员自我修养之性能优化篇,第11张

OnLowMemory()是Android提供的API,在系统内存不足,所有后台程序(优先级为background的进程,不是指后台运行的进程)都被杀死时,系统会调用OnLowMemory

一般来说有四种,分别为BlockCanay、ANR-WatchDog、SafeLooper和FileObserver


https://www.xamrdz.com/bigdata/7bx1890531.html

相关文章: