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累加起来就会影响越来越大。
网友评论