Android性能优化(四):内存优化

Android性能优化(四):内存优化

性能优化系列文章:

Android性能优化(一):APP启动优化
Android性能优化(二):UI布局优化
Android性能优化(三):响应优化
Android性能优化(四):内存优化

前言

在讲内存优化之前,我们先讲一下GC回收机制。Java相比于C语言不同的地方在于,Java不需要手动释放对象内存,JVM中的垃圾回收器会自动回收。但是这种自动回收是会出错的,而这种出错就会导致内存的泄漏。

1.垃圾回收

1.1 什么是垃圾?

Java中的垃圾是指在内存中没有被调用的对象。JVM中使用“可达性分析”的算法来判断对象是否可以被回收。通过一组名为“GC Root”的对象作为起点,直接或者间接被“GC Root”引用的为不可回收对象,否则为可回收对象。如下图所示:
在这里插入图片描述

1.2 什么时候回收?

以下两种情况会触发垃圾回收:

  1. Allocation Failure:在堆内存中分配时,如果因为可用剩余空间不足导致对象内存分配失败,这时就会触发一次GC。
  2. System.gc():在应用层,主动调用这个方法来请求一次GC。

2. Android内存泄露及管理

  1. 内存溢出(OOM)和内存泄露(对象无法被回收)的区别;
  2. 引起内存泄露的原因;
  3. 内存泄露检测工具 ------>LeakCanary

2.1 内存溢出与内存泄漏区别

  • 内存溢出 out of memory:是指程序在申请内存时,没有足够的内存空间供其使用,出现out of
    memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。内存溢出通俗的讲就是内存不够用。
  • 内存泄露memory leak:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

2.2 内存泄漏原因

  1. Handler 引起的内存泄漏。
    解决:将Handler声明为静态内部类,就不会持有外部类SecondActivity的引用,其生命周期就和外部类无关,如果Handler里面需要context的话,可以通过弱引用方式引用外部类。

  2. 单例模式引起的内存泄漏。
    解决:Context是ApplicationContext,由于ApplicationContext的生命周期是和app一致的,不会导致内存泄漏。

  3. 非静态内部类创建静态实例引起的内存泄漏。
    解决:把内部类修改为静态的就可以避免内存泄漏了

  4. 非静态匿名内部类引起的内存泄漏。
    解决:将匿名内部类设置为静态的。

  5. 注册/反注册未成对使用引起的内存泄漏。
    解决:注册广播接受器、EventBus等,记得解绑。

  6. 资源对象没有关闭引起的内存泄漏。
    解决:在这些资源不使用的时候,记得调用相应的类似close()、destroy()、recycler()、release()等方法释放。

  7. 集合对象没有及时清理引起的内存泄漏。
    解决:通常会把一些对象装入到集合中,当不使用的时候一定要记得及时清理集合,让相关对象不再被引用。

2.3 如何检测内存泄漏?

2.3.1 使用AS中的Profiler工具进行追踪检测
在这里插入图片描述
2.3.2 使用LeakCanary进行检测
1、添加依赖:

debugimplementation 'com.squareup.leakcanary:leakcanary-android:1.3'
releaseimplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'

2、创建APP继承Application,添加如下代码:

private RefWatcher refWatcher;
@Override
public void onCreate() {
    super.onCreate();
    if (LeakCanary.isInAnalyzerProcess(this)) {
        // This process is dedicated to LeakCanary for heap analysis.
        // You should not init your app in this process.
        return;
    }
    refWatcher = LeakCanary.install(this);
}

public static RefWatcher getRefWatcher(Context context) {
    MyApplication application = (MyApplication) context.getApplicationContext();
    return application.refWatcher;
}

3、在MainActivity的onDestroy()方法中添加如下代码:

@Override
protected void onDestroy() {
    super.onDestroy();
    RefWatcher refWatcher = MyApplication.getRefWatcher(this);
    refWatcher.watch(this);
}

好了,这样就可以监控内存是否泄露。

猜你喜欢

转载自blog.csdn.net/weixin_42574892/article/details/107331721