Android性能优化基础概念

120 阅读5分钟
  1. ANR

ANR(Applicatino not responding)是指程序无响应,主要原因为:

  1. 主线程被io操作阻塞(4.0后网络io不允许主线程中)。
  2. 主线程做了耗时任务超过 5秒。
  3. Service做了耗时操作超过20秒,这是由于service默认执行在主线程,可以使用IntentService 。
  4. BroadcastReceiver的onReciver做了耗时操作超过10秒。

解决方式:

  1. 开一个子线程,使用Handler来处理。
  2. 使用AsyncTask来处理耗时任务。
  1. 内存溢出

内存溢出主要是由于加载大的图片引起的。解决方式:

  1. 及时释放bitmap,调用.recycler(Bitmap会占用java内存和c(native)内存,java内存会自动释放,c内存需要手动释放)。
  2. 使用lru 最近最少使用

LruCache来存储对象put(key,value),,使用的使用LinkHashMap()。

  1. 计算inSampleSize

官方提供的方法,使用BitmapFactory.Options来计算inSampleSize(图片的缩略比)

  1. 缩略图

使用Options的inJustDecodeBounds属性来处理加载缩略图

  1. 三级缓存

内存,本地,网络。

  1. 内存抖动

内存抖动是指内存在短时间内频繁地分配和回收,而频繁的gc会导致卡顿,严重时和内存泄漏一样会导致OOM。

常见的内存抖动场景:

  1. 循环中创建大量临时对象;
  2. onDraw中创建Paint或Bitmap对象等;

内存抖动的原因:

瞬间产生大量的对象会严重占用新生代的内存区域,当达到阀值,剩余空间不够的时候,就会触发GC。系统花费在GC上的时间越多,进行界面绘制或流音频处理的时间就越短。即使每次分配的对象占用了很少的内存,但是他们叠加在一起会增加Heap的压力,从而触发更多其他类型的GC。这个操作有可能会影响到帧率,并使得用户感知到性能问题。

  1. 内存泄漏

Android性能优化:我总结了关于内存泄漏的所有知识

wiki:常见的内存泄露场景及修复方法参考

1.单例模式

public class SingleInstanceTest { 

    private static SingleInstanceTest sInstance; 

    private Context mContext; 

    private SingleInstanceTest(Context context){ 

        this.mContext = context; 

    } 

    public static SingleInstanceTest newInstance(Context context){ 

        if(sInstance == null){ 

            sInstance = new SingleInstanceTest(context); 

        } 

        return sInstance; 

    }

}

上面是一个比较简单的单例模式用法,需要外部传入一个 Context 来获取该类的实例,如果此时传入的 Context 是 Activity 的话,此时单例就有持有该 Activity 的强引用(直到整个应用生命周期结束)。这样的话,即使该 Activity 退出,该 Activity 的内存也不会被回收,这样就造成了内存泄露,特别是一些比较大的 Activity,甚至还会导致 OOM(Out Of Memory)。

解决方式:

 this.mContext = context.getApplicationContext(); 

可以看到在 SingleInstanceTest 的构造函数中,将 context.getApplicationContext() 赋值给 mContext,此时单例引用的对象是 Application,而 Application 的生命周期本来就跟应用程序是一样的,也就不存在内存泄露。

2.内部类导致内存泄漏

非静态内部类会默认持有外部类的引用。会导致内部类的生命周期过长。

正确的做法就是修改成静态内部类。

3.Handler

 Thread.sleep( 8000 ); 

时消息会继续存在主线程消息队列中8秒钟,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。

Handler 是个很常用也很有用的类,异步,线程安全等等。如果有下面这样的代码,会发生什么呢? handler.postDeslayed ,假设 delay 时间是几个小时… 这意味着什么?意味着只要 handler 的消息还没有被处理结束,它就一直存活着,包含它的 Activity 就跟着活着。

我们来想办法修复它,修复的方案是 WeakReference ,也就是所谓的弱引用。垃圾回收器在回收的时候,是会忽视掉弱引用的,所以包含它的 Activity 会被正常清理掉。

解决方式:

1.静态内部类

2.弱引用

3.注意在onDestroy中移除消息

  1. UI卡顿

  1. 在UI线程中做轻微耗时操作,会导致UI线程卡顿
  2. 布局Layout过于复杂,无法再16ms内完成渲染 60fps-->16ms

60ms一帧 每过16ms就会更新一下ui,要达到60ms一帧,否则可能会卡顿

  1. 同一时间动画执行的次数过多,导致cpu或gpu负载过重。
  2. View过度绘制,导致某些像素在同一时间内被绘制多次,从而导致cpu,gpu负载过重。

overdraw

  1. view频繁的触发measure。layout,导致measure。layout累计耗时过多以及整个view频繁的重新渲染
  2. 内存频繁触发Gc过多,导致展示阻塞渲染操作
  3. 屯余资源及逻辑导致加载和执行缓慢

解决ui卡顿:

  1. 布局优化 include,merge,viewsuble
  2. 背景和图片等内存分配优化
  1. 冷启动优化

冷启动笔记

  1. 内存优化

  1. 分配机制

为每一个进程分配一个小额的内存,然后根据需要分配更多内存。

  1. 回收机制

Android的目的是尽可能的运行多个进程,这样可以让用户不用每次都重新开启,而是恢复。当内存紧张时会按等级杀死进程。前台进程>可见进程>服务进程>后台进程(lru)>空进程。

优化方法:

  1. 当Service完成任务后,尽量停止它。
  2. 在UI不可见的时候,释放掉一些只有UI使用的资源
  3. 在系统内存紧张的时候,尽可能多的释放掉非重要的资源。
  4. 避免滥用Bitmap导致的内存浪费。
  5. 尽量使用少的依赖注入框架