OOM问题

作者: hhxx2yd | 来源:发表于2018-07-02 19:27 被阅读0次

OOM是开发中会经常遇见的一类问题,其中很多原因是可以在写代码阶段就可以排查出来的,本文结合之前解决的OOM的问题,列举了常见的代码编写时的注意事项。

static 引用

OOM问题的根源其实就是由于生命周期的不同步导致一些内存无法释放,常见的就是拥有长生命周期的引用了短生命周期的,导致其无法释放,这里面最常见的当属static引用:

DrmManager.getInstance().init(this);

Activity的onCreat方法中进行init操作,看着没什么问题继续往下走,主要关注传入的this最后到了哪里:

private static MtkDrmManager mMtkDrmManager = null;

public static MtkDrmManager getInstance(Context context) {
    if(mMtkDrmManager == null) {
        mMtkDrmManager = new MtkDrmManager(context);
    }

    return mMtkDrmManager;
}

从上面代码可以看到mMtkDrmManager 这个static变量最终引用了这个this,而this就是我们在上面传入的Activity,如果你这样写代码就会导致传入的Acitivity被泄露。

如何修改?
因static的变量是伴随整个进程的,其生命周期很长,因此需要找到匹配其生命周期的,那么一般来说就进程context来替代Acitivity。

DrmManager.getInstance().init(this.getApplicationContext());

Fragment泄露

这个容易被忽视,看下如下代码:

public void initSlomoEngine(LaunchThemeListener launchThemeListener) {
    this.mLaunchThemeListener = launchThemeListener;
    mSlowMoEngine = new SlowMoEngine();
    mSlowMoEngine.init(this);
}

Activity的init方法,再看调用这个init的地方:

mContext.initSlomoEngine(this);

上面的方法是在Fragment中调用的,将fragment传入。这样写代码会有什么问题呢?
Activity中的mLaunchThemeListener会持有Acitivity的应用,当fragment销毁后,因其被持有导致无法释放对应的内存,fragment被泄露,泄露的内存只能等到Acitivity销毁后才能释放。

如何修改?
也很简单,就是在fragment生命周期结束的时候,将mLaunchThemeListener的引用置null,具体代码修改如下:

//Fragment onDestroy方法
 public void onDestroy() {
        mContext.destorySlomoEngine();
}

//Acitivty 置null操作
public void destorySlomoEngine() {
    mLaunchThemeListener = null;
    mSlowMoEngine = null;
}

线程泄露

应用的线程一定要留意线程的创建和结束时机,如果出现不匹配的情况则很容易引起线程泄露,参考如下代码:

//Acitivity的onResume()调用如下方法开启线程
public void resume() {
    if (mSource != null) {
        mSource.addContentListener(mSourceListener);
    }
    mReloadTask = new ReloadTask();
    mReloadTask.start();
}
//Acitivity的onStop()调用如下方法结束线程
public void pause() {
    if (mReloadTask != null) {
        mReloadTask.terminate();
        mReloadTask = null;
    }
}

上述线程的创建可结束并不匹配,在一些场景中会出现问题,如当页面有弹出框出现时, Activity什么周期会走onPause,然后当弹出框消失会走onResume方法。如果不断重复上面的场景,则会发现线程在不断的被创建,但是并没有被合理的结束,因为在这种场景下Activity的onStop方法并没有被调用。

如何修改?
这个问题是在项目中真实遇到的问题,修改的方法就是把线程创建放在onStart方法中,这样就可以和onStop进行对应,从而避免问题。

如何排查OOM问题?

除了写代码的时候注意一些坑之外,如何主动的排查代码中存在的一些内存泄露隐患呢?Android lint也许会有一些帮助,可以在Android studio中找到:

Analyze--> Inspect Code

这个操作会对全部代码进行扫描,给出优化意见,耗时较长。具体优化项可以看下面的截图


Lint.png

如果只是想针对内存泄露做检查,可在参考上面的图中只勾选Android > Lint > Performance进行排查,或者直接通过具体的name来排查单条case,输入关键字leak过滤即可。

Analyze--> Run Inspection by name


Leak.png

总结

OOM问题其实是需要开发者重视的,因为每一个小的泄露都是在侵占这用户的内存资源,多个APP累加起来就会影响越来越大。

相关文章

  • (12)Redis大KEY定位及优化

    问题:出现OOM报错: OOM command not allowed when used memory > ‘m...

  • OOM问题

    1、什么是oom当前占用的内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存限制就会抛出的Out Of ...

  • OOM问题

    OOM是开发中会经常遇见的一类问题,其中很多原因是可以在写代码阶段就可以排查出来的,本文结合之前解决的OOM的问题...

  • OOM问题

    体现APP稳定性的重要数据就是Crash率,众多crash种最棘手最难定位的是OOM问题。APP中所有的内存泄漏都...

  • OOM问题

    什么是oom? 当前程序占用的内存加上我们申请的内存资源超过了Dalvik虚拟机的最大内存限制,就会抛出Out o...

  • 一次解决Android OOM的经历

    OOM OOM(Out Of Memory)是Android应用开发中相信每个人都遇到过的问题,而OOM在cras...

  • Android性能调优:记一次解决OOM的经历

    OOM OOM(Out Of Memory)是Android应用开发中相信每个人都遇到过的问题,而OOM在cras...

  • 全方位性能调优:一次解决Android OOM的经历

    OOM OOM(Out Of Memory)是Android应用开发中相信每个人都遇到过的问题,而OOM在cras...

  • Java服务,内存OOM问题如何快速定位

    Java服务,内存OOM问题如何快速定位 Java服务出现了OOM(Out Of Memory)问题,总结了一些相...

  • ResourceExhaustedError

    问题:ResourceExhaustedError (see above for traceback): OOM ...

网友评论

      本文标题:OOM问题

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