美文网首页Android葵花宝典APP开发经验总结Android Other
手把手教你在Android Studio 3.0上分析内存泄漏

手把手教你在Android Studio 3.0上分析内存泄漏

作者: 容华谢后 | 来源:发表于2017-11-01 07:28 被阅读4305次
    封面

    戳我下载 Android Studio 3.0

    这个不用梯子我会告诉你吗

    1.写在前面

    Google在上周发布了Android Studio 3.0的正式版本,周四早晨在上班的地铁上就看到群里在沸沸扬扬的讨论关于3.0版本的各种坑,啊,不对,各种特性,到公司之后就迫不及待的更新了3.0版本,嗯,还算顺利,只遇到了一个坑,一切都在happy的进行着。

    什么,你以为我想要写遇到的坑是什么,呵呵哒,我才不会告诉你,等等。。。手里的板砖先放下,一会说还不行吗,今天我们主要来聊聊如何在Android Studio 3.0上分析内存泄漏,文章的内容很简单,但是自己摸索还是需要一些时间的,所以就在这里记录下来分享给大家。

    2.强大的Android Profiler

    戳这里查看官方文档

    在3.0版本中,android使用了新的性能分析工具Android Profiler来代替原有的Android Monitor,使用方式和原来类似,都可以分析CPU、内存和网络的使用情况,但是功能强大了很多。

    开始使用

    还记得我之前写过一篇文章《Android 使用RxLifecycle解决RxJava内存泄漏》,本文将以这篇文章里的Demo为例,使用Android Studio 3.0再次分析一下内存泄漏。

    首先点击工具栏中的Profile按钮将待分析的App安装到设备上,也可以直接安装,在AS底部选择Android Profiler按钮:

    将待分析的APP安装到设备上

    可以看到有下面的提示,大概意思是不能在当前进程进行更高级的分析:

    不能在当前进程进行更高级的分析

    点击Run Configuration进去看看,发现不能勾选开关,提示gradle插件版本太低,需要2.4以上版本才可以,嗯,那就更新一下:

    更新gradle插件版本

    已经更新到3.0版本了,可以勾选开关了,点击确定:

    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0'
    }
    
    勾选开关

    又来一个警告,大概意思是说,你的gradle版本已经升级到3.0了,需要和26.0.2版本的构建工具搭配才更好,好好好,听你的:

    更新26.0.2版本的构建工具

    更新完成之后,需要再次运行一下App,如果还提示不能进行更高级的分析,请重启Android Studio,重启还不好,没关系,反正今天也用不到它,不要打我,下面来看下正常的Android Profiler:

    Android Profiler

    点击MEMORY进入内存详情,在这里可以实时查看内存的占用情况:

    内存详情

    内存泄漏分析

    我们先写个会发生内存泄漏的程序分析一下:

    public class RxLifecycleComponentsActivity extends RxAppCompatActivity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_rxlifecycle);
            ButterKnife.bind(this);
    
            initData();
        }
    
        private void initData() {
            // 每隔1s执行一次事件
            Observable.interval(1, TimeUnit.SECONDS)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Observer<Long>() {
                        @Override
                        public void onSubscribe(@NonNull Disposable d) {
    
                        }
    
                        @Override
                        public void onNext(@NonNull Long aLong) {
                            Log.i("接收数据", String.valueOf(aLong));
                        }
    
                        @Override
                        public void onError(@NonNull Throwable e) {
    
                        }
    
                        @Override
                        public void onComplete() {
    
                        }
                    });
        }
    }
    

    很简单,每隔1s发送一条数据,因为关闭Activity之后没有取消订阅,RxJava还继续持有Activity的引用,所以在内存回收的时候,该Activity不会被回收,由此引发内存泄漏。

    下面反复打开关闭页面5次,然后手动GC(点击左上角的垃圾桶图标),发现内存占用并没有减少:

    内存泄漏分析

    分析一下当前的内存堆栈情况(点击垃圾桶图标右侧的图标):

    分析内存堆栈情况

    选择按包名查找,找到当前测试的Activity,发现存在5个实例,由此可见,内存已经发生了泄漏:

    内存泄漏

    防止内存泄漏

    修改一下上面的代码,在关闭Activity时取消订阅:

    public class RxLifecycleComponentsActivity extends RxAppCompatActivity {
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_rxlifecycle);
            ButterKnife.bind(this);
    
            initData();
        }
    
        private void initData() {
            // 每隔1s执行一次事件
            Observable.interval(1, TimeUnit.SECONDS)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .compose(this.<Long>bindUntilEvent(ActivityEvent.DESTROY))
                    .subscribe(new Observer<Long>() {
                        @Override
                        public void onSubscribe(@NonNull Disposable d) {
    
                        }
    
                        @Override
                        public void onNext(@NonNull Long aLong) {
                            Log.i("接收数据", String.valueOf(aLong));
                        }
    
                        @Override
                        public void onError(@NonNull Throwable e) {
    
                        }
    
                        @Override
                        public void onComplete() {
    
                        }
                    });
        }
    }
    

    反复打开页面5次,手动GC,看下当前的堆栈情况,可以看到当前已经没有RxLifecycleComponentsActivity的实例存在了:

    无内存泄漏

    OK,到这里,在Android Studio 3.0上分析内存泄漏就学习完了,赶快去动手试试吧!

    3.更新Android Studio遇到的问题

    编译的时候报错:

    Error:(41, 0) Cannot set the value of read-only property 'outputFile' for ApkVariantOutputImpl_Decorated{apkData=Main{type=MAIN, fullName=debug, filters=[]}} of type com.android.build.gradle.internal.api.ApkVariantOutputImpl.
    

    发现是在gradle里打包输出apk的代码出的问题,原代码是这样的:

    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            def file = output.outputFile
            String apkName = "APK_NAME" + defaultConfig.versionName.replace(".", "_") + ".apk"
            output.outputFile = new File(file.parent, apkName)
        }
    }
    

    修改成这样就可以了:

    applicationVariants.all { variant ->
        variant.outputs.all {
            outputFileName = "APK_NAME" + defaultConfig.versionName.replace(".", "_") + ".apk"
        }
    }
    

    4.写在最后

    戳我下载 Android Studio 3.0

    戳我下载本文使用的测试Demo

    相关文章

      网友评论

      • BestMidsolo:不知道楼上说“学到不少”的几位用没用过之前的MAT,,不知道他们学到了什么
      • 94438f03c6bc:的确学到了不少,感谢楼主。
      • 2967cb319240:大佬您好问个问题,按照这么玩那MAT是否还有用分必要呢?求指一条明路
        刺客的幻影:具体定位可以用LeakCanary
        2967cb319240:@容华谢后 哎 具体如何定位泄漏是个挺有难度的内容 感觉这块内容真不是一下就能搞明白的 谢谢楼主的分享
        容华谢后:一些简单的内存泄漏可以用MAT来看看,复杂的还是用这个吧https://github.com/square/leakcanary
      • 08_carmelo:最关键的地方没有讲到:
        选择按包名查找,找到当前测试的Activity,发现存在5个实例,由此可见,内存已经发生了泄漏。

        怎么找到内存泄露的地方呢? 你这个demo是自己知道泄露在什么地方,实际场景一个Activity可能被很多地方持有context引用的
        JohnnyMan:使用LeakCanary库,可以定位到具体类的某个方法
        94438f03c6bc:是啊, 没讲到关键点
        容华谢后:@08_carmelo 找具体内存泄漏的地方还比较困难,大佬有什么好的建议吗?
      • 城平京:学到了,谢谢
      • e289cd30b54e:大佬,如何进一步定位泄露的位置,代码太长无从看起
        e289cd30b54e:@容华谢后 2.3有个analyse我还觉得挺方便的,3.0好像是给去掉了?
        容华谢后:点击发生泄漏的实例,可以在下面看到引用详情,Shallow Size代表该对象本身占用内存的大小,Retained Size代表该对象被释放后,垃圾回收器能回收的内存总和,不过这样看好像不太容易定位具体的泄漏位置,如果你以后有更好的方法可以分享下,借助第三方工具可以定位到具体的泄漏位置https://github.com/square/leakcanary
      • 3e6043b91737:为什么我的手动GC后还有好几个activity 对象的实例
        容华谢后:@番茄味_a886 之前也有同学反馈过这个问题,不过在我这试就没问题,可以换个设备试试,或者用其他的内存泄漏检测工具检测一下看看。
        3e6043b91737:@容华谢后 我自己写的 leak测试没有泄漏 不过activity有好几个很奇怪
        容华谢后:@番茄味_a886 用的是文章里的Demo测试吗,手动GC之后内存占用减少了吗,换个设备试试呢?
      • 6fd1d9051260:你好,我看了你的更新后,用Android Profiler时候,当数据线拔出,在插上后Android Profiler读不出来手机了,但是logcat是能显示的,也能打印log,请问你遇到这种情吗?该如何解决?
        6fd1d9051260:@容华谢后 嗯,知道了谢谢,我的模拟器好像一个样子。我昨天试了重启AS,是可以的。可是我的数据线处于半坏的状态,不停重启,有点烦的。。。最后谢谢你的不啬指教。:blush: :blush:
        容华谢后:@也少图 遇到过,真机不行,虚拟机可以,后来自己好了 😂,可以试试重启AS,或者重新运行一下程序。
      • Android_JiaJia:studio3.0,点击dump java heap按钮,界面闪了一下,并没有出现heap分析页面。之前还是好的,现在突然不行了。网上搜索了下,没找到解决方法(重启studio也没用),不知道楼主遇到过没或者有什么解决办法:smile:
        容华谢后:@Android_JiaJia AS有个清理缓存的功能,不知道管不管用,再不行就卸载重装😂
      • 祖国花朵Code:是只可以在5.0以上系统才可以用吗
        祖国花朵Code:@祖国花朵Code 在6.0上面都正常,运行程序也正常,就是profiler运行报这个错。
        祖国花朵Code:@容华谢后 :relaxed: 我在4.4系统上随便写了个demo,跑了下报这种错,java.lang.UnsatisfiedLinkError: dlopen failed: cannot locate symbol "strtof" referenced by "libsupportjni.so"...
        容华谢后:@祖国花朵Code 应该不是吧,还没试过5.0以下的系统,明天我试下哈
      • 请叫我章鱼哥:您好,大佬问一下在Activity/Fragment中进程被回收,那么未解除注册类似EventBus的unregister和RXjava的解绑,这样会存在内存泄漏的情况吗?:smile:
        请叫我章鱼哥:@容华谢后 :+1: :+1: 谢谢大佬解答疑惑
        容华谢后:如果Activity/Fragment进程被回收了,就不存在内存泄漏了,我想你应该指的是关闭页面吧。
        如果RxJava订阅中存在对当前Activity/Fragment引用的话(就像文中的例子),此时不会被回收,就会引起内存泄漏。
        EventBus在页面关闭后没有取消注册,这个会不会引起内存泄漏我没有试过,但是肯定会有一定几率导致crash,因为关闭Activity/Fragment后,内存回收机制不会立即对其进行回收,此时还在消息订阅状态,但是其中的资源有可能已经被置空了,如果这时有消息过来就会引起空指针。
      • 0445981d6022:嗨,你好,请问你试过3.0network里面的网络请求分析吗?我尝试了一下抓包,发现只能得到自己发起请求的相关参数,而响应的数据却得不到,不知道是啥原因。
        请叫我章鱼哥:我也是这样的情况:sleepy:
        0445981d6022:@容华谢后 对的,显示为no preview available,不知道是啥原因。
        容华谢后:我的可以啊,响应的数据得不到的话,Response那栏是空的吗?
      • addqian:先mark住,谢谢博主的分享
        容华谢后:@addqian :grin:

      本文标题:手把手教你在Android Studio 3.0上分析内存泄漏

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