欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

性能优化

程序员文章站 2022-07-02 22:54:56
...

软解时代:2.3时代,所有的绘图由CPU完成,通过软件画图
硬解时代:2.3之后,增加了GPU,同时把很多绘图工作交给GPU进行渲染
黄油时代:4.1之后通过VSYNC垂直同步机制和多缓冲机制进一步提高绘制效率
异步绘制时代:5.0之后,系统增加了Render Thread通过这个线程进行异步绘制,即使某一帧发生延迟也不会影响下一帧的绘制

尽量降低布局层次,提高view的使用率include,或者多使用组合控件,减少view的数量
减少过度绘制,比如背景颜色全部设置成了蓝色,但是下边一半的高度都被按钮或者图片遮挡了,那么我们就过度绘制了半个屏幕的大小
自定义View 通过clipRect减少重绘区域
控件与主题颜色相同可移除控件背景
控件重叠摆放可以改善布局方式,避免重叠
DDMS中的Tracer for OpenGL 通过追踪进程可以查看GPU绘制Frame的详细时间

通过adb shell dumpsys gfxinfo > /sdcard/gfx.txt 可以将前一段时间的渲染数据导出到gfx.txt,然后通过excel可以将这些数据可视化
通过adb shell dumpsys gfxinfo <package name> framestats 可以获取更详细的页面渲染信息

检测ANR

通过使用adb pull /data/anr/traces.txt ~/Downloads/可以将Exception的调用栈导出

TraceView

可以得到单次执行最耗时的方法和执行次数最多的方法
这两个数据与CPU的性能息息相关,也极大影响着UI性能
我们可以通过代码分析指定的代码块

Debug.startMethodTracing();
...代码...
Debug.stopMethodTracing();

执行完毕之后会自动将数据保存到sdcard下,采集到的数据可以通过sdk下的traceView工具打开
CPU Time/Call 方法平均占用CPU时间的长度,即可以寻找单次执行最耗时的方法
Call+Recur Calls/Total方法调用次数的多少,即可以寻找调用次数最多的方法

Systrace

在4.3系统以上可以通过python运行如下指令

python systrace.py --time=10 -o mytrace.html sched gfx view wm

在代码中可以使用sdk提供的Trace类来增加自定义的Trace Tag,以便分析代码块的性能问题

Trace.beginSection("ProcessPeople");
try{
  //code for Jane task...
   }finally{
    Trace.endSection();
   }
启动时间

对于Activity来说,启动时首先执行的是onCreate(),onStart(),onResume()这些生命周期函数,但是即使这些生命周期函数执行结束了,应用也不算完全启动,还需要等待view树全部构建完毕,一般认为setContentView中的View全部显示结束了,算是应用完全启动了。
ADB计算启动时间
adb shell am start -W com.xys.preferencetest/.MainActivity
该指令一共给出了三个时间
ThisTime:最后一个启动的Activity的启动耗时
TotalTime:自己的所有Activity的耗时
WaitTime: ActivityManagerServiceie 启动App的Activity时的总时间(包括当前Activity的onPause和自己的Activity的启动)
每次给出的时间可能不一样,而且应用从首次安装启动到后面每次正常启动,时间都会不同,区别在于系统是否要分配进程空间

内存探究

在对象不需要的时候确保对象被销毁
如果对象没有被销毁,则该对象一定是可以复用的对象,而不是存在多个
栈:存放基本类型的数据,对象的引用和函数地址,由系统控制
堆:存放对象本身和数组,由开发者控制
静态域:存储静态变量
常量池:存储常量
寄存器:用于存储指令,地址,数据

堆:由GC控制,变量生命周期结束后,由GC系统决定何时回收 慢
栈:由虚拟机控制,变量生命周期结束后,由虚拟机释放该变量占用的内存空间 快

adb dumpsys meminfo 可以dump当前系统的内存使用状态,如果不指定包名的话
adb dumpsys procstats 收集的数据为指定时间段内的内存分配状况
在AndroidMainifest文件中申请的android:largeHeap="true"虽然可以提高app的内存分配,但是也会造成由于内存过大而导致的GC速度减慢
我们可以通过ActivityManager的getMemoryClass()获取单个app内存的最大值可以通过ActivityManager的getLargeMemoryClass获取单个app内存最大值(即申请的large heap)
这些阈值是定义在系统rom中的,在编译时就已经写入系统了,通过查看系统属性,就可以找到这些值,例如单个app的最大值

adb shell getprop | grep dalvik.vm.heapgrowthlimit

Android系统限制的是Java Heap的申请,Native Heap的内存分配是由系统控制的不受大小限制
OpenGL的很多api同样是不受Java Heap限制的,因为OpenGL将RAM的一部分作为显存使用

系统内存警告

  1. onLowMemory 是系统低内存管理系统发出的系统警告,当该回调被触发,所有进程优先级为Background的进程都已经被杀掉了,此时app还可以进行自己app资源的释放,避免被进一步杀死
registerComponentCallbacks(new ComponentCallbacks(){
    public void onConfigurationChanged(Configuration newConfig){
    }
    public void onLowMemory(){
    }
});

通过Context.registerComponentCallbacks(ComponentCallbacks callbacks)就可以在任何地方注册ComponentCallbacks监听onLowMemory回调了

  1. onTrimMemory返回的信息更加丰富,只要满足了触发条件,系统就会返回内存警告信息,在onTrimMemroy回调中,包含了一个int类型的参数level,代表着警告的级别

TRIM_MEMORY_UI_HIDDEN 表示应用程序的所有UI界面被隐藏了,即用户点击了Home键或者Back键导致应用的UI界面不可见.这时候应该释放一些资源,他是在onStop()方法之前被调用的

运行时内存容量(三级)此时app处于前台运行状态,但系统内存已经快达到阈值了:

第一级警告:
TRIM_MEMORY_RUNNING_MODERATE 表示应用程序正常运行,并且不会被杀掉

第二级警告:
TRIM_MEMORY_RUNNING_LOW 表示内存已经接近阈值了,应用程序正常运行,并且不会被杀掉。但是目前手机的内存已经非常低了,我们应该去释放掉一些不必要的资源以提升系统的性能,同时这也会直接影响到我们应用程序的性能

第三级警告:
TRIM_MEMORY_RUNNING_CRITICAL 表示即将杀掉自己的app,应用程序仍然正常运行,但是系统已经根据LRU缓存规则杀掉了大部分缓存的进程了。这个时候我们应当尽可能地去释放任何不必要的资源,不然的话系统可能会继续杀掉所有缓存中的进程,并且开始杀掉一些本来应当保持运行的进程,比如说后台运行的服务

缓存时内存容量(三级)当app处于后台运行状态时,例如按home键退出到后台,与运行时类似也是三级警告

第一级警告
TRIM_MEMORY_BACKGROUND 表示已经准备把app列为准备杀掉的对象,手机目前内存已经很低了,系统准备开始根据LRU缓存来清理进程。这个时候我们的程序在LRU缓存列表的最近位置,是不太可能被清理掉的,但这时去释放掉一些比较容易恢复的资源能够让手机的内存变得比较充足,从而让我们的程序更长时间地保留在缓存当中,这样当用户返回我们的程序时会感觉非常顺畅,而不是经历了一次重新启动的过程

第二级警告
TRIM_MEMORY_MODERATE 表示app已经准备把app列为准备杀掉的对象,手机目前内存已经很低了,并且我们的程序处于LRU缓存列表的中间位置,如果手机内存还得不到进一步释放的话,那么我们的程序就有被系统杀掉的风险了。

第三级警告
TRIM_MEMORY_COMPLETE 表示LMK即将杀掉自己的app,手机目前内存已经很低了,并且我们的程序处于LRU缓存列表的最边缘位置,系统会最优先考虑杀掉我们的应用程序,在这个时候应当尽可能地把一切可以释放的东西都进行释放

 ComponentCallbacks2 callbacks2=new ComponentCallbacks2() {
            @Override
            public void onTrimMemory(int level) {

            }

            @Override
            public void onConfigurationChanged(Configuration newConfig) {

            }

            @Override
            public void onLowMemory() {

            }
        };

在引入OnTrimMemory之前都是使用OnLowMemory回调,需要知道的是,OnLowMemory大概和OnTrimMemory中的TRIM_MEMORY_COMPLETE级别相同,如果你想兼容api<14的机器,那么可以用OnLowMemory来实现,否则你可以忽略OnLowMemory,直接使用OnTrimMemory即可

CPU Top命令

top -n 1 -m 5 -d 1
—> 刷新一次,前五个进程,间隔一秒
m最多显示多少个进程
n刷新次数
d刷新间隔时间
s排序方式

PID 进程PID
PR 进程优先级
S 进程状态(S是休眠,R 正在运行,Z 僵尸进程)
THR 进程所含线程数
VSS 虚拟耗用内存
RSS 实际物理使用内存
PCY 线程调度策略
UID 用户IDE

获取电量耗电数据
先要开启full-wake-history

adb shell dumpsys batterystats --enable full-wake-history

不过在检测前最好先清空Battery history避免在dump信息的时候抓取过多的信息

adb shell dumpsys batterystats --reset

重新连接adb后使用如下命令来获取电量数据

adb shell dumpsys batterystats > batterystats.txt

然后下载historian.py文件解析数据(https://github.com/google/battery-historian
不过在检测前最好先清空Battery history避免在dump信息的时候抓取过多的信息

python historian.py batterystats.txt> batterystats.html

转载于:https://www.jianshu.com/p/e9e3f437fa67