当前位置:   article > 正文

Android 内存泄漏检测之Profiler_android profile监控发现2个leak

android profile监控发现2个leak

说到Android的内存泄漏,很多人下意识想到:LeakCanary  ,导入依赖,运行后直接看通知栏结果。

但是,你们有没有想过,LeakCanary   检查内存泄漏的范围?其实,LeakCanary   这家伙能且只能检测Activity的内存泄漏

划重点:LeakCanary只能检测Activity的内存泄漏

为什么呢?

LeakCanary的原理

因为LeakCanary 通过 ActivityLifecycleCallbacks 是监听了整个应用的Activity的创建和销毁,当一个Activity销毁后,

就对这个Activity赋上弱引用,然后手动GC,去促使垃圾回收器回收垃圾。然后在垃圾队列里查看是否有刚才销毁的Activity,

如果没有,就说明这个Activity泄漏了。

 

这个设计到很多源码的跟踪,还有Java垃圾回收器的机制,在这就不详解了。我之前的博客说过垃圾回收机制的。可以看去。

但是问题来了,如果老子不是 Activity泄漏呢?是一个Fragment泄漏呢?是一个实体对象泄漏了呢?怎么检测呢?

这个LeakCanary  都是检测不出来的。。。。。。所以,这个时候需要另外的工具,

 

噔噔瞪!!!!!!Profiler 出场了。Android studio 自带的工具。

特别说明一下,Profiler 的样式每个版本都有差异的,这个帖子以Android studio3.4为基准

 

1:Profiler在哪里? 

运行了项目,就可以在底部栏看到 Profiler了

 

2:Profiler怎么用? 

好了,我们的应用运行起来了。我们点一下Profiler,看到的效果

可以看到 Profiler栏目有三个指数,CPU,MEMORY,NETWORK,分别指:CPU使用状况,内存使用状况和网络状况

现在我们是要分析内存。所以我们点一下 MEMORY,他会单独展示 内存使用,如下面:

这个界面,是应用运行时的内存状态。看截图即可。。

通过Profiler分析内存一般有两种方法,

分析内存方法一 ,进出页面,强制手动触发GC,Dump Heap分析

好了,我们先构造一个会内存泄漏的页面,比如:

  1. class LeakActivity : AppCompatActivity() {
  2. companion object {
  3. fun launch(context: Context) {
  4. context.startActivity<LeakActivity>()
  5. }
  6. lateinit var leakActivity: LeakActivity
  7. }
  8. override fun onCreate(savedInstanceState: Bundle?) {
  9. super.onCreate(savedInstanceState)
  10. setContentView(R.layout.activity_leak)
  11. leakActivity = this
  12. }
  13. }

静态变量引用了当前的Activity。

然后我们的步骤是:

1>进入当前泄漏的页面,然后退出去

2>手动点击垃圾桶按钮,触发GC,触发回收垃圾对象。(这样保证需要回收的对象都不在内存里面)

3> 过3秒下载点击heap堆内存数据,(为什么过3秒呢?因为保证垃圾回收器有足够时间回收完所有需要被回收的对象)

4>等待几秒后,Android studio 会自动生成堆内存数据。比如下面截图:

会生成这么一个内存数据分析图。只要在这个分析目录里面的,就是说明在垃圾回收器回收后的内存数据。如果你的对象按理应该在内存中消失的,但却在这个目录里出现了,就说明你的对象无法被垃圾回收器回收,泄露了。

这个目录,选择按照我们包名目录去展示数据。

比如我现在应用的包名叫:com.leo.dicaprio.myutilapp 我们就会展开com目录去找。

其他目录可能是系统或者其他一些模块,我们基本上没必要去分析。我们只需要分析我们的应用有没有泄露即可。

然后,从上面代码看出,我们怀疑  LeakActivity 泄露,因为从代码上看他被静态变量引用。

所以我们一直依循这个 LeakActivity所在包路径找下去,看他是否还在内存里?看下截图

果不其然,他还在内存里面。没有被回收,泄露了。我们双击一个这个泄露的LeakActivity,

他会 弹出 instance View,然后再点击里面的 LeakActivity,会看到 Reference窗口,

Reference 列表就是展示所有对LeakActivity的引用列表,我们就要冲这个列表找出那个引用导致LeakActivity无法被回收。

来,上一波图:

看到了把。一个名字叫 leakActivity 变量(看清楚大小写),引用了LeakActivity(看清楚大小写),

然后再继续点击去,发现 leakActivity 变量 是在 LeakActivity里面的。这样就非常清晰了。。。。

在这里说一下,heap Dump右边有四个参数,具体是:

Alloc Count:Java堆中的实例个数
Native Size:native层分配的内存大小。
Shallow Size:Java堆中分配实际大小
Retained Size:这个类的所有实例保留的内存总大小(并非实际大小)

 

分析内存方法二,进出页面,手动触发GC分析,Record分析 

前面一种是手动触发gc,然后看内存。但是,你们有没有发现,引用队列有很多乱七八糟的系统引用。这个需要一定得功底才能查找出那些是系统里面的,那些是自己应用里面的引用。

这个时候,我们想要看下第二种办法。好,我们来第二种分析:就是内存录制。录制某一时间内存的状况。然后也是通过 

引用队列去定位分析,但是他有一个好处,什么好处呢?先看下面,先构造一个内存泄漏的例子:

  1. public class Leak2Activity extends AppCompatActivity {
  2. public static void launch(Context context) {
  3. Intent intent = new Intent(context, Leak2Activity.class);
  4. context.startActivity(intent);
  5. }
  6. @Override
  7. protected void onCreate(@Nullable Bundle savedInstanceState) {
  8. super.onCreate(savedInstanceState);
  9. setContentView(R.layout.activity_leak2);
  10. postHandler();
  11. }
  12. private void postHandler() {
  13. new Handler().postDelayed(new Runnable() {
  14. @Override
  15. public void run() {
  16. }
  17. },999999999);
  18. }
  19. }

然后操作步骤是:

1:点击record按钮,开始录制内存

2:进入Leak2Activity,然后退出

3:手动GC,3秒后点击按钮停止录制。

4:等待生成内存数据,分析。。。。

即:

【1:点击record按钮,开始录制内存】

【2:进入Leak2Activity,然后退出

此处省略截图

【3:手动GC,3秒后点击按钮停止录制

【4:等待生成内存数据,分析

 

看分析图,录制出来的内存数据分析图。

还是选择包名去分配目录

然后看到我们的 Leak2Activity 还在内存,说明泄漏。然后我们点击Leak2Activity&1,弹开InstanceView

然后再点击Leak2Activity&1,看Allocation Call Back,神奇的一幕出现了,

看到Leak2Activity 类里面的方法名。没错,就说明这两个类型里的这两个方法 对 Leak2Activity引用了。

然后刚才不说了这个方法有好处吗,说的好处就是它给你精确定位到那个方法进行对这个类引用了

然后我们双击这其中一个方法名,Android Studio 直接跳到这个方法的代码处。

 

然后看代码就知道这个方法是为什么会造成内存泄漏了。

总结

所以最后总结一下,这两种方法的却别:

方式1:强制GC,生成heap Dump,分析内存引用。

好处:不需要知道对象创建时间,任何时候可以查看堆内存数据

缺点:定位不到相关代码,太多系统的混淆引用。

方式2:录制内存数据,进出页面,分析内存数据

好处:可以定位到相关代码,不用看太多系统的混淆引用。

缺点:需要知道对象创建时间,只能在内存录制时间内可以查看

 

当然,现在展示的是Activity,其实同样可以检测任何类的实例是否泄漏。原理都是一样的。

 

 

 

以上代码亲测没问题,有问题请留言谢谢!

 

 

 

 

 

 

 

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号