美文网首页Android进阶之路Android开发Android技术知识
Android性能优化:你的一些使用细节可能会引起严重的内存泄漏

Android性能优化:你的一些使用细节可能会引起严重的内存泄漏

作者: Z_萧晓 | 来源:发表于2020-02-26 11:35 被阅读0次

    前言

    在Android中,内存泄露的现象十分常见;而内存泄露导致的后果会使得应用Crash。常见引发内存泄露原因主要有:

    1. Static关键字修饰的成员变量
    2. 非静态内部类 / 匿名类
    3. 日常使用(Context、WebView等)

    今天,我将详细介绍日常的使用会导致的内存泄露,主要包括:集合类、资源对象使用后未关闭、Context、WebView和Adapter。

    知识储备

    a. 内存泄漏简介

    即 ML (Memory Leak),指 程序在申请内存后,当该内存不需再使用 但 却无法被释放 & 归还给 程序的现象

    b. 内存泄漏的影响:

    a. 容易使得应用程序发生内存溢出,即 OOM
    b. 内存溢出的简介:

    c. 内存泄露的本质原因

    结论:本该被回收的对象 因为某些原因 而不能被回收,从而继续停留在堆内存中

    解释

    1. ”本该被回收“ = 该对象 已不需再被使用
    2. ”因某些原因 而 不能被回收“的原因 = 有另外1个正在使用的对象持有它的引用,即:无意识地持有对象

    本质原因:持有引用者的生命周期 > 被引用者的生命周期,从而 当后者需结束生命周期被销毁时,无法被正确回收。

    总结
    a. 当1个对象已不需再被使用、本该被GC回收时,而因有另外1个正在使用的对象持有它的引用 从而导致它不能被程序回收 而停留在堆内存中
    b. 本质原因 = 持有引用者的生命周期 > 被引用者的生命周期

    特别注意
    从机制上的角度来说,由于 Java存在垃圾回收机制(GC),理应不存在内存泄露;出现内存泄露的原因仅仅是外部人为原因 = 无意识地持有对象引用,使得 持有引用者的生命周期 > 被引用者的生命周期

    d. Android 内存管理机制

    e. 类型

    日常使用中,容易发生内存泄漏常见情况有4种:

    1. 集合类
    2. 资源对象使用后未关闭
    3. Context
    4. WebView
    5. Adapter

    下面,我将上述所有情况进行逐一详细介绍。

    1. 集合类

    1.1 内存泄露原因

    集合类 添加元素后,仍引用着 集合元素对象,导致该集合元素对象不可被回收,从而 导致内存泄漏

    1.2 实例演示

    // 通过 循环申请Object 对象 & 将申请的对象逐个放入到集合List
    List<Object> objectList = new ArrayList<>();        
           for (int i = 0; i < 10; i++) {
                Object o = new Object();
                objectList.add(o);
                o = null;
            }
    // 虽释放了集合元素引用的本身:o=null)
    // 但集合List 仍然引用该对象,故垃圾回收器GC 依然不可回收该对象
    

    1.3 解决方案

    集合类 添加集合元素对象 后,在使用后必须从集合中删除。由于1个集合中有许多元素,故最简单的方法 = 清空集合对象 & 设置为null

     // 释放objectList
            objectList.clear();
            objectList=null;
    

    2. 资源对象使用后未关闭

    2.1 泄露原因

    对于资源的使用(如 广播BraodcastReceiver、文件流File、数据库游标Cursor、图片资源Bitmap等),若在Activity销毁时无及时关闭 / 注销这些资源,则这些资源将不会被回收,从而造成内存泄漏。

    2.2 解决方案

    在Activity销毁时 及时关闭 / 注销资源。
    // 对于 广播BraodcastReceiver:注销注册
    unregisterReceiver()
    
    // 对于 文件流File:关闭流
    InputStream / OutputStream.close()
    
    // 对于数据库游标cursor:使用后关闭游标
    cursor.close()
    
    // 对于 图片资源Bitmap:Android分配给图片的内存只有8M,若1个Bitmap对象占内存较多,当它不再被使用时,应调用recycle()回收此对象的像素所占用的内存;最后再赋为null
    Bitmap.recycle();
    Bitmap = null;
    
    // 对于动画(属性动画)
    // 将动画设置成无限循环播放repeatCount = “infinite”后
    // 在Activity退出时记得停止动画
    

    3. Context

    3.1 内存泄漏原因

    a. 当 拥有该Activity Context参数对象仍在使用 、而该Activity需销毁时,该Activity则由于被保持引用而无法被回收,从而造成内存泄露
    b. 即,当拥有Context参数的对象的生命周期 > 该Context参数的生命周期时,则容易出现内存泄露

    3.2 解决方案

    对Context的引用不要超过它本身的生命周期:

    a. 如:尽量使用ApplicationContext代替ActivityContext
    b. 因ApplicationContext会随着应用程序的存在而存在,而不依赖于activity的生命周期

    3.3 特别注意

    a. 在Android中,通常可使用Context对象有2种:Activity、Application
    b. 当类 / 方法需Context对象时,常优先使用 Activity作为Context参数;此时该对象对整个Activity保持引用

    4. WebView

    4.1 内存泄漏原因

    不再使用WebView对象后 无销毁,导致占用的内存长期无法被回收,从而造成内存泄露

    4.2 解决方案

    通过多线程在不使用WebView对象时进行销毁

    4.3 示例

    如:

    1. 为WebView开启另1个进程
    2. 通过AIDL与主线程进行通信,WebView所在的进程可根据业务的需要,选择在合适的时机销毁,从而达到内存的完整释放

    5. Adapter

    5.1 内存泄漏原因:

    a. 在滑动ListView获取最新的View时,容易频繁生成大量对象
    b. 即 每次都在getView()中重新实例化1个View对象
    c. 不仅浪费资源、时间,也将使得内存占用越来越大,从而使得内存泄露

    5.2 解决方案

    a. 使用缓存的convertView
    b. 直接使用 ViewHolder

    5.3 特别注意

    • 初始时,ListView会根据当前的屏幕布局 从Adapter中实例化一定数量的 View对象,同时ListView会将这些view对象缓存起来
    • 当向上、下滚动ListView时,原先位于最上、下面的List Item的View对象会被回收,然后被用来构造新出现的最下面的list item
      • 这个构造过程由getView()方法完成:来向ListView提供每一个item所需要的view对象
      • getView()的第2个形参View convertView = 被缓存起来的list item的view对象
      • 初始化时缓存中没有view对象,则convertView = null

    6. 总结

    本文全面总结了日常使用中的内存泄漏情况,总结如下

    至此,关于日常使用中的内存泄漏情况讲解完毕。

    作者:carsonho

    最后我想说:对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!

    这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司19年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。

    相信它会给大家带来很多收获:

    上述【高清技术脑图】以及【配套的架构技术PDF】可以 关注我 【主页简介】 或者【简信】免费获取

    Android学习PDF+架构视频+面试文档+源码笔记

    当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。

    相关文章

      网友评论

        本文标题:Android性能优化:你的一些使用细节可能会引起严重的内存泄漏

        本文链接:https://www.haomeiwen.com/subject/tkfmchtx.html