记一次内存泄漏问题排查

Posted alexkn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次内存泄漏问题排查相关的知识,希望对你有一定的参考价值。

通过MonitoSDK的Sample App进行试用时,发现存在部分内存泄漏的情况,leakcanary直接弹出提示如下

技术分享图片

 

可以看到MonitorDBActivity的instance导致泄漏。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_db);

        ButterKnife.bind(this);
    }

    @OnClick(R.id.inputData)
    public void inputData() {

        EditText input = (EditText) findViewById(R.id.inputTestData);
        int num = Integer.valueOf(input.getEditableText().toString());
        ErrorReporter reporter = ACRA.getErrorReporter();
        CrashReportDataFactory factory = null;
        try {
            factory = Reflect.on(reporter).get("crashReportDataFactory");
        } catch (ReflectException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < num; i++) {
            final ReportBuilder builder = new ReportBuilder();
            builder.exception(new Exception(i + ""));
            final CrashReportData crashReportData = factory.createCrashData(builder);
            MLog log = null;
            try {
                log = new MLog(crashReportData.toJSON().toString());
            } catch (JSONReportBuilder.JSONReportException e) {
                e.printStackTrace();
            }
            MLogStoreMgr.getInstance(this).add(log);
        }
    }

可以看到,log相关操作只有MLogStoreMgr.getInstance(this).add(log);这一行代码,继续debug,可以看到最后底层执行的是

        if(!UploadTask.isRunning()) {
            TaskExecutor.getInstance().postDelayed(1, new UploadTask() {
                public void onUploadExcuted() {
                    if(UploadEngine.this.bRunning) {
                        UploadEngine.this.calNextInterval();
                        if(TaskExecutor.getInstance().hasCallbacks(1)) {
                            TaskExecutor.getInstance().removeCallbacks(1);
                        }

                        if(!UploadTask.isRunning()) {
                            TaskExecutor.getInstance().postDelayed(1, this, UploadEngine.this.mPeriod);
                        }
                    }

                }

                public void deleteError() {
                }
            }, this.mPeriod);
        }

没错,就是这个postDelayed导致的。这可是在主线程执行的。因此因为这个方法,导致主线程MainActivity的引用无法被释放,直到消息被looper处理掉。因此,做了如下改造。

技术分享图片

 

以上是关于记一次内存泄漏问题排查的主要内容,如果未能解决你的问题,请参考以下文章

记一次使用windbg排查内存泄漏的过程

记一次线上内存溢出问题排查过程

记一次 .NET 某外贸Web站 内存泄漏分析

记一次内存溢出查找分析文档

记一次通过Memory Analyzer分析内存泄漏的解决过程

记一次 .NET 某电厂Web系统 内存泄漏分析