Android性能优化笔记

致某大神:如果你看到这个文章,我只是拿CSDN做个笔记,全无靠你的经验招摇撞骗的意思。跪拜先。

工具

  • TraceView中各列的含义,其实分为几类:
    • 时间计量:cpu/real time,Cpu时间和墙上时间
    • 运行时间统计:Incl/Excl,时间是否包含本函数中子函数的调用时间
列名 描述
Name 该线程运行过程中所调用的函数名
Incl/Excl Cpu/real Time 某函数占用的时间
Call+Recur Calls/Total 某函数被调用次数以及递归调用次数/总调用次数
Cpu Time/Call 某函数调用CPU时间与调用次数的比。相当于该函数平均执行时间
Real Time/Call 同CPU Time/Call类似,只不过统计单位换成了真实时间
  • 获得调试GPU过度绘制的数据,使用adb shell dumpsys gfxinfo packageName,能够得到详细数据
  • Threads查看线程时,各项的含义:
名字 解释
ID JAVA的线程id
Tid Linux的线程id
Status 线程状态
utime 用户代码执行时间
stime 系统代码执行时间
name 线程名

status包括:

- running:运行中
- sleeping:执行了Thread.sleep()
- monitor:等待接受一个监听锁
- wait:执行了Object.wait()
- timedwait:执行了Object.wait(time)
- native:执行native代码
- vmwait:等待虚拟机
- zombie:僵尸线程
  • SysTrace追踪所有代码的执行情况
  • Tracer for OpenGL ES查看渲染的细节情况
  • 分阶段进行trace,避免把特定时期的严重问题掩盖掉

语言

  • 容器类都是以乘以因子的方法扩容的(HashMap *2,ArrayList *1.5),这样来讲,默认大小初始化的容器只会有数个固定大小,如果需存储的数据大小固定,很可能会造成由于扩容引起的内存问题。
  • instancof已经包括判空了
  • 字符串在使用过程中推荐使用直接赋值的方式创建,因为系统维护了常量池
  • StringBuilder/Buffer 也都是自动扩容,因子约为1.5。尽量给初始化大小,否则扩容很容易有内存GC和碎片的问题
  • 做字符串拆分的时候使用StringTokenizer来实现,避免使用String类的split方法。StringTokenizer与indexOf性能相近
  • 复用StringBuilder的时候,不要用toString,而是用substring(0)。这样delete/setLength之后,不会重复分配内部的char[]
  • 靠谱的单例,如果单例很耗内存,可以持久化+释放
  • 内部类访问private成员会有多次函数调用,可能有性能问题,改为包权限即可
  • 函数的final入参都是使用copy value的方法,所以要注意内存问题
  • Java读写文件的时候,会有字符串到utf8byte的转换,可能很好时,造成大量GC
  • NIO,FileChannel性能有很大的提升。结合MappedByteBuffer(应该就是linux系统里面的mmap)性能提升更大
  • 同时过多的IO文件操作将会导致整体文件操作性能的明显下降

GC

  • Dalvik GC的类型:
    • GC_FOR_MALLOC:分配内存时
    • GC_CONCURRENT:空闲空间小于阈值时
    • GC_EXPLICIT:有人主动调用gc时
    • GC_BEFORE_OOM:OOM之前尝试的gc
  • GC过程中会进行堆大小调整,申请大对象后立刻释放,很可能导致下次申请对象时发生GC,并把堆大小变小
  • Dalvik默认使用了Mark and Sweep回收算法。所以对于Dalvik来说,首先要尽量避免频繁生成很多临时小变量,另一个又要尽量去避免产生很多长生命周期的大对象。否则小变量多次回收会产生很多碎片,大对象又会难以释放,进一步分割内存空间
  • ART GC类型:
    • kGcCauseForAlloc:分配内存,会stop the world
    • kGcCauseBackground:阈值
    • kGcCauseExplicit:显示调用
    • kGcCauseForNativeAlloc:native
    • kGcCauseCollectorTransition: Mark-Sweep GC 和Compacting GC 切换的时候触发
    • kGcCauseDisableMovingGc
    • kGcCauseTrim
    • kGcCauseHomogeneousSpaceCompact
  • 在没有出作用范围(当前所在的大括号)前,对象是不会被回收的。即使出了作用范围,由于变量作用域(栈帧中的局部变量表)对象可能被复用,只要在作用域外没有新的对象出现,都可能会不能回收。栈帧
  • 使用操作资源的独立进程,使用系统保证在进程退出的时候资源一定释放
  • Android 的内存管理是按进程做的,所以可以多进程多骗内存空间

杂技

  • SQL实务是在commit时统一进行IO的,多条sql使用事务会提高性能
  • 复杂Activity在不可见之后要释放图片资源,最好复写back键,不销毁Activity
  • 获取当前手机运行的app、安装的app等函数可能在不同设备上有很大的时间差距
  • 锁分离
  • 如果调用次数过多,不要用handler.post而是使用handler.sendMessage。这样会少很多对象的创建
  • 全Activity只有一个OnXXXListener是为了减少对象的数量
  • JSON比Parcel快,Parcel比Serializable快,都是数倍起的差距

SharedPreference

  • SharedPreference.apply是异步的,commit是同步的
  • SharedPreference是用xml做的,所以所有xml中的特殊字符都要额外处理,影响性能
  • SharedPreference在ContextImpl里有静态引用,一经读入,永不释放
  • 同一个SharedPreference中的内容一定要相关,修改频率接近。因为读写都是全文件的

Layout

  • Canvas.draw每调用一次,都会增加一层绘制,这也是过度绘制的来源之一。可以缓存到bitmap上,也可以clipRect(硬件加速下不生效)。硬件加速的兼容性问题
  • 可以在RelativeLayout中加入Invisible(不是Gone)的锚点View,用来布局。比如左右平分父View就可以用一个view centerInParent,再两个View分别toLeft和toRight来实现
  • ListView、ScrollView、TextView的创建非常耗性能
  • RelativeLayout会一直有两次measure的情况,所以尽量不要有太多子View
  • LinearLayout如果要用weight,子View一定要用0dp的宽高
  • AdapterView中,如果显示的数量不变,最好直接修改对应View的内容,这样只会有一次invalidate,notifyDataSetChanged导致的一系列状态保持操作可以跳过
  • 如果View大小能事先固定,不要用wrap_content/match_parent,避免在measure中有过多计算,特别是TextView

- EditText在没有输入法的时候一定要让其失去焦点,否则光标会持续刷新整个页面

你可能感兴趣的:(android,性能优化)