Android 性能优化--内存篇

Android内存优化是我们性能优化工作中比较重要的一环,主要包括两方面的工作:

  1. 优化RAM,即降低运行时内存。目的是防止程序发生OOM异常,以及降低程序由于内存过大被LowMemoryKiller(LMK)机制杀死的概率。同时,不合理的内存使用会使GC次数大大增多,从而导致程序变卡。
  2. 优化ROM,即降低程序占ROM的体积,防止ROM空间不足导致程序无法安装等问题。

前言

Android中关于内存优化的问题主要包括三个方面:

  • Memory Leaks 内存泄漏
  • OutOfMemory 内存溢出
  • Memory Churn 内存抖动

同时,和内存相关的三个主要数据为:

  • 总内存
  • 系统可用内存
  • 当前App可用内存

扩大内存

  1. 申请更大内存

每一个Android设备都会有不同的RAM总大小与可用空间,因此不同设备为App提供了不同大小的heap限制,可以通过调用getMemoryClass()来获取当前App的可用heap大小。

在一些特殊情景下,可以通过在manifest的application标签下添加largeHeap=true属性来声明一个更大的heap空间,之后可以通过getLargeMemoryClass()来获取到一个更大的heap大小。但这不是该值得提倡的方法,因为使用额外的内存会影响系统整体的用户体验,并且会使得GC的运行时间更长。在任务切换时,系统的性能会变得大打折扣。

而且, large heap并不一定能够获取到更大的heap。在某些有严格限制的机器上,large heap的大小和通常的heap size是一样的。因此即使你申请了large heap,你还是应该通过执行getMemoryClass()来检查实际获取到的heap大小。

  1. 创建多进程

内存泄漏

对象由于编码错误或系统原因,仍然存在着对其直接或间接的引用,导致系统无法进行回收。
内存泄漏引发的常见问题有:

  • 应用卡顿,响应速度慢(内存占用高时JVM虚拟机会频繁触发GC);
  • 应用被从后台进程处理为空进程;
  • 应用莫名崩溃(引起OOM);

常见泄漏类型

单例模式导致的内存泄漏

使用单例持有Context,需要记得释放,或使用全局上下文。

静态变量导致的内存泄漏

除了避免显示地使用静态变量引用拥有自己生命周期的对象外,也需要注意一些隐式的使用,如下:

private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
    super.onCreate(state);
    TextView label = new TextView(this);
    label.setText("Leaks are bad");
    if (sBackground == null) { 
        sBackground = getDrawable(R.drawable.large_bitmap);
    }
    label.setBackgroundDrawable(sBackground);
    setContentView(label);
}

sBackground是一个静态的变量,我们虽然没有显式地保存Context的引用,但是,当Drawable与View连接之后,Drawable就将View设置为一个回调,由于View中是包含Context的引用的,所以,实际上我们依然保存了Context的引用。这个引用链如下:Drawable->TextView->Context
所以,最终该Context也没有得到释放,发生了内存泄露。

解决方案

  • 尽量避免静态变量引用资源耗费过多的对象,如Context,同时注意对静态对象的释放。
  • Context尽量使用ApplicationContext。
  • 使用WeakReference代替强引用,比如可以使用WeakReference mContextRef;

非静态内部类导致的内存泄漏

尽量不

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