玩安卓必须要掌握的性能优化之内存泄漏

说起性能优化,大多数脑海里便会出现启动优化、UI绘制优化、内存优化等等。之前我也一直在做这些优化,一直没有勇气看内存泄漏的问题,觉得太难,但是,再难也要看啊,跑不了,那么就来吧(做完发现其实也不难)。

内存泄漏的分析很简单,Android Studio中就自带了工具profile:

直接点击这个按钮就会运行应用并进入相应界面:

点击图片中的MEMORY就进入内存的页面:

然后点击左上角的下载按钮(Record旁边),进入详细页面,

可以选为查看包内容,查看下当前运行的活动,然后右击选中内容,选择export,自定导出位置。

导出后需要使用SDK中的hprof-conv工具,这里windows的用户可以直接进入安卓的sdk文件夹下运行cmd即可,Mac用户可以配置一个全局变量,由于我的系统版本是10.15,这里我就写zsh的配置方法了。

1.打开终端
2.打开 ~/.zshrc文件(如果无,则自动新建)
命令:

// 打开 ~/.zshrc文件(如果无,则自动新建)
open ~/.zshrc

3.设置环境变量

export PATH=${PATH}:/Users/zhujiang/Library/Android/sdk/platform-tools

4.保存并退出编辑
5.刷新环境变量生效

source ~/.zshrc

到这里就都可以使用hprof-conv工具了,需要输入以下命令将你导出的hprof文件转换成mat-hprof文件,命令如下:

hprof-conv -z 导出的文件.hprof 转换文件-mat.hprof

完成之后会出现的转换的文件,接下来需要下载能分析MAT的工具,一般使用Memory Analyzer,下面是下载地址:

https://www.eclipse.org/mat/downloads.php

下载完毕后双击文件如果报错的话,这是eclipse的一个bug。

解决办法: 右键mat显示包内容,进入Contents->MacOS下面,会有一个MemoryAnalyzer的命令。

打开终端,进入此路径找到MemoryAnalyzer,运行以下命令:

./MemoryAnalyzer -data dump文件所在文件夹路径

这样即可启动成功:

打开之后选择如下选项打开刚才转换完成的文件:

打开之后选择我下面的选项,然后点击finish,如果出错别管它,继续进行:

进入之后选择Overview,然后点击Histogram。

之后就可以进入类的页面,可以在里面进行筛选:

下面是筛选的方法:

找见需要优化的类,按照下面的方法打开:

打开之后是如下的页面:

发现有一个mContext持有活动的引用,导致活动无法销毁。找到原因之后进行解决,咱们需要短了它的引用链,使GC可以清理调它。代码不多,在活动的onDestory()中进行销毁就行。

public static void fixInputMethodManagerLeak(Context destContext) {
        if (destContext == null) {
            return;
        }

        InputMethodManager imm = (InputMethodManager) destContext.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm == null) {
            return;
        }

        String [] arr = new String[]{"mCurRootView", "mServedView", "mNextServedView"};
        Field f;
        Object obj_get;
        for (String param : arr) {
            try {
                f = imm.getClass().getDeclaredField(param);
                if (!f.isAccessible()) {
                    f.setAccessible(true);
                }
                obj_get = f.get(imm);
                if (obj_get instanceof View) {
                    View v_get = (View) obj_get;
                    if (v_get.getContext() == destContext) { // 被InputMethodManager持有引用的context是想要目标销毁的
                        f.set(imm, null); // 置空,破坏掉path to gc节点
                    } else {
                        // 不是想要目标销毁的,即为又进了另一层界面了,不要处理,避免影响原逻辑,也就不用继续for循环了
                        break;
                    }
                }
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
    }

好了,这就是一个简单的内存泄漏问题。如果你的页面中有其他页面没有销毁,那就证明你的页面存在内存泄漏,就需要来这样进行查看。使用Mat工具方法有很多,大家可以多搜索一下。先到这里吧。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

朱 江

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值