博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 检测内存泄露
阅读量:6240 次
发布时间:2019-06-22

本文共 2467 字,大约阅读时间需要 8 分钟。

Android 检测内存泄漏,必须使用方便强大到灭绝人性的 。

leakcanary 是 公司开发的,square 拥有众多强大的 Android 开源项目,如,OkHttp、retrofit、otto、picasso,简直撑起了Android 开发的半边天。

一行代码就可以捕找到已经泄漏的内存泄漏,并且显示出出现内存泄漏的变量或线程、泄漏时的引用路径和出现泄漏的地方。

使用

1.添加依赖

dependencies {   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'   testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' }复制代码

2.初始化 leakcanary

public class ExampleApplication extends Application {  @Override public void onCreate() {    super.onCreate();    if (LeakCanary.isInAnalyzerProcess(this)) {      // This process is dedicated to LeakCanary for heap analysis.      // You should not init your app in this process.      return;    }    LeakCanary.install(this);    // Normal app init code...  }}复制代码

用例

写一段内存泄露的代码。

MainActivity.java

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);    }    public void onClick(View view) {        test();        finish();        startActivity(new Intent(MainActivity.this, Main2Activity.class));    }    // 这里会发生内存泄漏    public void test() {        new Thread(new Runnable() {            @Override            public void run() {                while (true) {                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }).start();    }}复制代码

MainActivity 中点击按钮后,'test()' 方法内部匿名内部类执行了耗时任务,并且同时 finish() 掉 MainActivity,但是此匿名内部类依然在运行任务,并且隐式的持有 MainActivity 引用,导致 MainActivity 不能及时被 GC 回收,导致内存泄露。

LeakCanary 检测出内存泄露后,会在状态栏显示一条通知,点进去就可以看到详细信息。如下图:

leak.png

含义:

标题栏显示内存泄露的类和泄露的内存大小,菜单栏提供分享出更详细的信息,包括堆栈信息或者 .hprof 文件。蓝色栏显示包名,第一行显示出现泄露的线程,下面几行显示所有的引用,最后一行显示泄露的类。

MainActivity$1.this$0 的含义:

符号 “$” 代表后者是前者的内部类,“.”就是对象调用方法那个点。

用 “.” 分为两部分,前面整体代表 MainActivity 的一个匿名内部类,用 1 表示,在这里代表 Runnable 匿名类,后面部分 this$0 整体代表外部类。

看到这个内存泄露信息,首先定位到 MainActivity 中,同时可以看得出是 MainActivity 的实例出现的内存泄露,并且发生在子线程中,看到代码,我们就可以确认肯定是在 Runnale 匿名内部类中隐式的引用了 MainActivity 导致的内存泄露。

在这里打一个断点:

break.png

可以看到匿名类内部存在一个外部 MainActivity 的引用。

找到原因就好办了,静态化匿名内部类就解决问题了:

// 静态public static void test() {    // ... }复制代码

break2.png

静态化之后,发现该匿名内部类中不在持有外部类 MainActivity 对引用,也就不会在 MainActivity 销毁后,出现内存泄露了。

本文由 创作,采用

国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名

你可能感兴趣的文章
ObjectOutputStream和ObjectInputStream
查看>>
南京大学周志华教授当选欧洲科学院外籍院士
查看>>
计算机网络与Internet应用
查看>>
oracle在线迁移同步数据,数据库报错
查看>>
linux性能剖析工具
查看>>
flutter中的异步
查看>>
计算机高手也不能编出俄罗斯方块——计算机达人成长之路(16)
查看>>
# 2017-2018-1 20155224 《信息安全系统设计基础》第七周学习总结
查看>>
scikit-learn预处理实例之一:使用FunctionTransformer选择列
查看>>
邮件客户端导入邮件通讯录地址薄
查看>>
Linux系统安装
查看>>
Cassandra监控 - OpsCenter手册
查看>>
一些关于写Java代码的建议
查看>>
网络社交如何保护个人隐私?做好这4步
查看>>
SQL*Plus中的Echo
查看>>
SEO基础知识8大精华文章之第一篇(连载)
查看>>
面向sql编程
查看>>
对前面的自定义的toast制作拖拽效果,以及双击居中效果
查看>>
如何规划构建一套大型的Citrix桌面虚拟化架构 - 后记
查看>>
animationFromTop
查看>>