Android内存泄漏个人理解与分析

今天整理一下关于内存泄漏和优化相关,这是个人最近心得,希望能够帮助读者。

下面我们便开始吧。

最近组内在讨论关于内存泄漏与优化的问题,每个人多多少少可能都会遇到这样的问题,总是觉得哪里会出现内存泄漏,而网上对内存泄漏和优化的文章有一大堆,每次看的总是觉得一时能够理解,但是自己却总是用不到或者想不透,最近颇有心得,下面来讲下关于这个问题,结合一些例子,优化和泄漏放在一起。

个人理解有以下几点:
1.首先,关于后台服务,别总是想着要保活,现在Google已经把app后台活动限制的死死的,别想着要反着来,人家这样做肯定是经过仔细考虑才发布的,而且每个版本都还要加强限制,不懂得小伙伴可以大概了解一下Doze模式下面程序活动情况,基本后台活动会不断延时进行,就连用的微信最近放久了也不及时不灵光了。
结论:服务Google推荐使用JobService,一般服务做前台就行,也可以用IntentService(如果与UI无交互)

2.应用返回为杀死,我们经常会在主页面重写返回,让用户点了back之后进入后台页面,这是不友好的。
建议:使用正常退出流程,让应用关闭当前页面,否则这部分页面任然占用内存,导致资源浪费

3.关于Context引用,有Activity的Context,而一般建议使用ApplicationContext,这样使对象引用的是Application,而不是页面的Context,否则存在内存泄漏,这个通俗易懂,但是什么情况是Context引用而容易导致内存泄漏呢,我整理了一下,用一句话来讲:线程或者静态对象直接或者间接引用了ActivityContext。

什么是直接引用?

1.静态对象引用

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
     //public static Object ref1;
        RefManager.ref1 = this;
    }
}

这是一个静态对象引用case,这里存在页面关闭activity任然被静态指向导致内存泄漏,我想这样的代码应该每人写。

2.线程引用

public class MyThread extends Thread{
    private Context mContext;

    public MyThread(Context mContext) {
        this.mContext = mContext;
    }
}

Thread mThread = new MyThread(this);
mThread.start();

这种case是线程直接引用Context,这种情况导致页面关闭但是Thread可能还没有执行完成导致Context被引用出现内存泄漏。

以上是2种直接引用this对象(Map引用也差不多),这2种情况都需要使用慎重,直接引用很容易排查,建议使用WeakReference或者在页面推出执行引用置空操作并且释放资源

3.间接引用:

关于间接引用,据我理解,其实就是 非静态内部类/匿名内部类 被静态或者线程引用,为什么这样理解呢?

3.1链式传递引用:顾名思义,就是一个A -> B -> T/S,那么T/S也是引用A的,举例如下:

MyObject obj = new MyObject(MainActivity.this);
Thread mThread = new MyThread(obj);
mThread.start();

这里MyObject对象对Activity引用,而该对象又被MyThread引用,这么按照传递的效果,那么Activity也是间接被MyThread引用了

3.2非静态内部类:

非静态内部类可以访问外部方法(静态内部类则不能访问),也就是说,非静态内部类默认可以完全访问外部方法,这样外部类就是默认被非静态内部类完全引用了,如果将这个非静态内部类传给静态变量或者线程,那么就好比 A -> B -> T/S , 其中A是Context/Activity,B在A里面属于非静态内部类, T/S是线程或静态变量,这样T/S就是间接引用A,在A关闭可以导致内存泄漏,当然了,这里需要注意的是可能B经过很多C或者D或者E,最后到T/S,这就存在一个链式间接引用,这条链上面的每个元素都不会被释放,导致泄漏。下面将结合3.3举例:

3.3匿名内部类:

匿名内部类同3.2非静态内部类,匿名内部类是由new创建并重写或者实现某个方法,假设在A中有个匿名内部类,那么匿名内部类重写或者实现的方法中可以调用A中所有方法,这就存在对A的引用,匿名内部类引用了A,这时候又和上面一样的case了,如果这个匿名内部类经过多次链式传递给了静态变量或者线程,那么页面关闭的时候,匿名内部类不会被释放,那么引用的A也不会被释放,导致内存泄漏,常见的有CallBack,Handler,new构造的所有对象重写或实现的方法会产生引用A内部方法,举个栗子:

public class MainActivity extends Activity{

    private void init(){
        //匿名内部类引用
        MyThread thread = new MyThread(new callBack1() {
            @Override
            public void onResult() {
                processResult();
            }
        });
        //非静态内部类引用
        thread.setCallBack2(new callBack2());
    }

    public interface callBack1{
        void onResult();
    }

    public class callBack2{
        public void invoke(){
            MainActivity.this.processResult();
        }
    }

    public void processResult(){
        //do something
    }
}

此例子是一个Activity里面有一个内部类CallBack2和一个接口,首先是非静态内部类,使用invoke方法调用Activity的onResult,其二是匿名内部类接口callBack1,这里内部类接口callBack1引用了this里面方法导致后台操作不会及时释放Context。

4.资源的打开与关闭

使用IO、File流或者Sqlite、Cursor等资源时要及时关闭,一般都是对应写注册与反注册, Open与Close

5.其他

耗时任务,属性动画间接引用View里面Context,Thread(Runnable),Timer引用This方法导致泄漏。

总结:
关于内存泄漏,目前个人理解就是对页面Context(this)的引用,直接或者间接引用,直接引用容易发现,间接引用需要追踪链接,不管是线程还是静态内部类,引用方法或者view都会造成内存泄漏。如果内部类并没有引用Context(this)里面的方法或者指向则不会造成泄漏

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,458评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,030评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,879评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,278评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,296评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,019评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,633评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,541评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,068评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,181评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,318评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,991评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,670评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,183评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,302评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,655评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,327评论 2 358

推荐阅读更多精彩内容

  • Android 内存管理的目的 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。简单粗...
    晨光光阅读 1,294评论 1 4
  • 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏大家都不陌生了,简单粗俗的讲,...
    宇宙只有巴掌大阅读 2,363评论 0 12
  • Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏...
    _痞子阅读 1,637评论 0 8
  • Android 内存泄漏总结 内存管理的目的就是让我们在开发中怎么有效的避免我们的应用出现内存泄漏的问题。内存泄漏...
    apkcore阅读 1,222评论 2 7
  • 新家搬到了高楼, 发现习惯住在平地上。 黄昏时打开了窗, 晚风竟来得猝不及防。 我俯瞰着窗外的广场, 花园里有人遛...
    遇上音阶阅读 283评论 0 0