探索 Android 内存优化方法( 四 )

  • ALPHA_8 只有 A 通道 , 占 8 位 , 也就是每个像素占 1 个字节
  • 5.3 Glide
    如果服务器返回给我们的图片是 200 * 200 , 但是我们的 ImageView 大小是 100 * 100 , 如果直接把图片加载到 ImageView 中 , 那就是一种内存浪费 。
    但是使用的 Glide 的话 , 那这个问题就不用担心了 , 因为 Glide 会根据 ImageView 的大小把图片大小调整成 ImageView 的大小加载图片 , 并且 Glide 有三级缓存 , 在内存缓存中 , Glide 会根据屏幕大小选择合适的大小作为图片内存缓存区的大小 。
    6. 什么是内存泄漏?6.1 内存泄漏简介
    内存泄漏指的是 , 当一块内存没有被使用 , 但无法被 GC 时的情况 。
    堆中一块泄漏的内存就像是地上一块扫不掉的口香糖 , 都很让人讨厌 。
    一个典型的例子就是匿名内部类持有外部类的引用 , 外部类应该被销毁时 , GC 却无法回收它 , 比如在 Activity 中创建 Handler 就有可能出现这种情况 。
    内存泄漏的表现就是可用内存逐渐减少 , 比如下图中是一种比较严重的内存泄漏现象 , 无法被回收的内存逐渐累积 , 直到无更多可用内存可申请时 , 就会导致 OOM 。
    探索 Android 内存优化方法

    文章插图
    6.2 常见的内存泄漏原因
    常见的造成内存泄漏的原因有如下几个 。
    6.2.1 非静态内部类
    1. 原因 非静态内部类会持有外部类的实例 , 比如匿名内部类 。匿名内部类指的是一个没有人类可识别名称的类 , 但是在字节码中 , 它还是会有构造函数的 , 而它的构造函数中会包含外部类的实例 。比如在 Activity 中以匿名内部类的方式声明 Handler 或 AsyncTask , 当 Activity 关闭时 , 由于 Handler 持有 Activity 的强引用 , 导致 GC 无法对 Activity 进行回收 。当我们通过 Handler 发送消息时 , 消息会加入到 MessageQueue 队列中交给 Looper 处理 , 当有消息还没发送完毕时 , Looper 会一直运行 , 在这个过程中会一直持有 Handler , 而 Handler 又持有外部类 Activity 的实例 , 这就导致了 Activity 无法被释放 。
    2. 解决 我们可以把 Handler 或 AsyncTask 声明为静态内部类 , 并且使用 WeakReference 包住 Activity , 这样 Handler 拿到的就是一个 Activity 的弱引用 , GC 就可以回收 Activity 。这种方式适用于所有匿名内部类导致的内存泄漏问题 。
    publicstaticclassMyHandlerextendsHandler{Activity activity;
    publicMyHandler(Activity activity){
    activity = newWeakReference<>(activity).get;
    }
    @Override
    publicvoidhandleMessage(Message message){
    // ...
    }
    }
    6.2.2 静态变量
    1. 原因 静态变量导致内存泄漏的原因是因为长生命周期对象持有了短生命周期对象的引用 , 导致短生命周期对象无法被释放 。比如一个单例持有了 Activity 的引用 , 而 Activity 的生命周期可能很短 , 用户一打开就关闭了 , 但是单例的生命周期往往是与应用的生命周期相同的 。
    2. 解决 如果单例需要 Context ,  可以考虑使用 ApplicationContext , 这样单例持有的 Context 引用就是与应用的生命周期相同的了 。
    6.2.3 资源未释放
    1. 忘了注销 BroadcastReceiver
    2. 打开了数据库游标(Cursor)忘了关闭
    3. 打开流忘了关闭
    4. 创建了 Bitmap 但是调用 recycle 方法回收 Bitmap 使用的内存
    5. 使用 RxJava 忘了在 Activity 退出时取消任务
    6. 使用协程忘了在 Activity 退出时取消任务
    6.2.4 Webview
    1. 原因 不同的 Android 版本的 Webview 会有差异 , 加上不同厂商定制 ROM 的 Webview 的差异 , 导致 Webview 存在很大的兼容问题 。一般情况下 , 在应用中只要使用一次 Webview , 它占用的内存就不会被释放 。
    2. 解决 WebView内存泄漏--解决方法小结
    7. 什么是内存抖动?7.1 内存抖动简介
    当我们在短时间内频繁创建大量临时对象时 , 就会引起内存抖动 , 比如在一个 for 循环中创建临时对象实例 。
    下面这张图就是内存抖动时的一个内存图表现 , 它的形状是锯齿形的 , 而中间的垃圾桶代表着一次 GC 。
    这个是 Memory Profiler 提供的内存实时图 , 后面会对 Memory Profiler 进行一个更详细的介绍 。


    推荐阅读