使用新版Android Studio检测内存泄露和性能

2023-05-16

文/于连林520wcf(简书作者)

原文链接:http://www.jianshu.com/p/216b03c22bb8


内存泄露,是Android开发者最头疼的事。可能一处小小的内存泄露,都可能是毁于千里之堤的蚁穴。怎么才能检测内存泄露呢?网上教程非常多,不过很多都是使用Eclipse检测的, 其实1.3版本以后的Android Studio 检测内存非常方便, 如果结合上MAT工具,LeakCanary插件,一切就变得so easy了。

熟悉Android Studio界面工欲善其事,必先利其器。

我们接下来先来熟悉下Android Studio的界面


内存分析界面

一般分析内存泄露, 首先运行程序,打开日志控制台,有一个标签Memory ,我们可以在这个界面分析当前程序使用的内存情况, 一目了然, 我们再也不需要苦苦的在logcat中寻找内存的日志了。

图中蓝色区域,就是程序使用的内存, 灰色区域就是空闲内存,

当然,Android内存分配机制是对每个应用程序逐步增加, 比如你程序当前使用30M内存, 系统可能会给你分配40M, 当前就有10M空闲, 如果程序使用了50M了,系统会紧接着给当前程序增加一部分,比如达到了80M, 当前你的空闲内存就是30M了。 当然,系统如果不能再给你分配额外的内存,程序自然就会OOM(内存溢出)了。 每个应用程序最高可以申请的内存和手机密切相关,比如我当前使用的华为Mate7,极限大概是200M,算比较高的了, 一般128M 就是极限了, 甚至有的手机只有可怜的16M或者32M,这样的手机相对于内存溢出的概率非常大了。

我们怎么检测内存泄露呢

首先需要明白一个概念, 内存泄露就是指,本应该回收的内存,还驻留在内存中。一般情况下,高密度的手机,一个页面大概就会消耗20M内存,如果发现退出界面,程序内存迟迟不降低的话,可能就发生了严重的内存泄露。我们可以反复进入该界面,然后点击dump java heap 这个按钮,然后Android Studio就开始干活了,下面的图就是正在dump


正在dump

dump成功后会自动打开 hprof文件,文件以Snapshot+时间来命名


内存分析结果

通过Android Studio自带的界面,查看内存泄露还不是很智能,我们可以借助第三方工具,常见的工具就是MAT了,下载地址 http://eclipse.org/mat/downloads.php ,这里我们需要下载独立版的MAT. 下图是MAT一开始打开的界面, 这里需要提醒大家的是,MAT并不会准确地告诉我们哪里发生了内存泄漏,而是会提供一大堆的数据和线索,我们需要自己去分析这些数据来去判断到底是不是真的发生了内存泄漏。


MAT主界面

接下来我们需要用MAT打开内存分析的文件, 上文给大家介绍了使用Android Studio生成了 hprof文件, 这个文件在呢, 在Android Studio中的Captrues这个目录中,可以找到


hprof目录]

注意,这个文件不能直接交给MAT, MAT是不识别的, 我们需要右键点击这个文件,转换成MAT识别的。


导出标准的hprof

然后用MAT打开导出的hprof(File->Open heap dump) MAT会帮我们分析内存泄露的原因


打开标准的hprof

自动分析内存泄露的原因

LeakCanary

上面介绍了MAT检测内存泄露, 再给大家介绍LeakCanary。
项目地址:https://github.com/square/leakcanaryLeakCanary
会检测应用的内存回收情况,如果发现有垃圾对象没有被回收,就会去分析当前的内存快照,也就是上边MAT用到的.hprof文件,找到对象的引用链,并显示在页面上。这款插件的好处就是,可以在手机端直接查看内存泄露的地方,可以辅助我们检测内存泄露.


手机端查看内存泄露.png

使用:
在build.gradle文件中添加,不同的编译使用不同的引用:

dependencies {  
      debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3' 
      releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'
 }

在应用的Application onCreate方法中添加LeakCanary.install(this),如下:

public class ExampleApplication extends Application  
  @Override  
  public void onCreate() { 
      super.onCreate();  
      LeakCanary.install(this);
   } 
}

应用运行起来后,LeakCanary会自动去分析当前的内存状态,如果检测到泄漏会发送到通知栏,点击通知栏就可以跳转到具体的泄漏分析页面。Tips:就目前使用的结果来看,绝大部分泄漏是由于使用单例模式hold住了Activity的引用,比如传入了context或者将Activity作为listener设置了进去,所以在使用单例模式的时候要特别注意,还有在Activity生命周期结束的时候将一些自定义监听器的Activity引用置空。

关于LeakCanary的更多分析可以看项目主页的介绍,还有这里
http://www.liaohuqiu.net/cn/posts/leak-canary-read-me/

追踪内存分配

如果我们想了解内存分配更详细的情况,可以使用Allocation Traker来查看内存到底被什么占用了。用法很简单:


点击追踪内存分配

点一下是追踪, 再点一下是停止追踪, 停止追踪后 .alloc文件会自动打开,打开后界面如下:


追踪内存结构展示


当你想查看某个方法的源码时,右键选择的方法,点击Jump to source就可以了

查询方法执行的时间

Android Studio 功能越来越强大了, 我们可以借助AS观测各种性能,如下图:


检测性能界面


Android studio2.1 界面发生了变化,功能没有太大区别:


新版本界面

如果我们要观测方法执行的时间,就需要来到CPU界面


追踪方法耗时

点击Start Method Tracking, 一段时间后再点击一次, trace文件被自动打开,


结果

非独占时间: 某函数占用的CPU时间,包含内部调用其它函数的CPU时间。
独占时间: 某函数占用CPU时间,但不含内部调用其它函数所占用的CPU时间。

我们如何判断可能有问题的方法?

通过方法的调用次数和独占时间来查看,通常判断方法是:

  1. 如果方法调用次数不多,但每次调用却需要花费很长的时间的函数,可能会有问题。
  2. 如果自身占用时间不长,但调用却非常频繁的函数也可能会有问题。

综述

上面给大家介绍了若干使用Android Studio检查程序性能的工具,工具永远是辅助,不要因为工具耽误太长时间。如果有问题,欢迎大家纠正。



文/于连林520wcf(简书作者)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用新版Android Studio检测内存泄露和性能 的相关文章

  • 检测到设备正在振动?

    我使用下面的代码来振动设备 public void vibrator try Vibrator vibrator Vibrator getSystemService Context VIBRATOR SERVICE vibrator vib
  • Android - 如何一次只允许播放一个 MediaPlayer 实例?

    我正在尝试创建一个简单的 Sound board Android 应用程序 使用 ListView 项目作为按钮 顺便说一句 我是一个新手程序员 我的想法是 我按下一个按钮 就会播放一个特定的声音文件 如果我在播放声音时按下任何按钮 它应该
  • 导航组件重复 NavArgs 的问题

    我有一个片段 class SomeFragment private val args by navArgs
  • Delphi XE7 Android 全屏(隐藏软键)

    如何在XE7中全屏显示 隐藏顶部 标题 和底部 软键 工具栏 在 XE6 中 我可以通过在应用程序部分写入来调整 AndroidManifest 以使我的应用程序全屏显示并且没有操作栏 android theme android style
  • (Ionic 2)尝试回退到 Cordova-lib 执行时发生错误:TypeError:无法读取未定义的属性“then”

    Edit 使用 ionic 2 时会发生这种情况 我知道它还不稳定 但我认为可能有一些解决方案 因为其他人似乎没有遇到这个问题 Edit end 由于某种原因 我在尝试使用 ionic build android 和 ionic build
  • 接近语法错误(代码1)插入Android SQLite

    我正在创建一个通讯录应用程序 用户可以在其中输入姓名 电子邮件地址和号码 我希望将此数据保存在数据库中 但我似乎无法使插入方法起作用 我收到的错误是 android database sqlite SQLiteException near
  • 获取 AlarmManager 中活动的 PendingIntents 列表

    我有办法获取活动列表PendingIntent在设备中 我开始工作AlarmManager我想看看我的PendingIntents 已正确创建和删除 也很高兴看到其他什么PendingIntent在那里 只是为了看看某些应用程序是否正在做一
  • 在我的Android中,当其他应用程序想要录制音频时如何停止录音?

    在我的应用程序中 服务通过 AudioRecord 持续录制音频 当我的应用程序运行时 其他与音频记录相关的应用程序 例如 Google 搜索 无法工作 如何知道何时有其他应用想要录制音频 以便我可以停止录制以释放资源 答案是MediaRe
  • Android Webview 图像未加载

    我制作了一个简单的应用程序WebView 但有些图片无法加载 正确 在我的电脑上 错误 在模拟器中 Correct 错误 没有横幅 于是我用Chrome debug进行调试 发现我的代码被改变了 我不添加像noscript or style
  • 将 JSON 参数从 java 发布到 sinatra 服务

    我有一个 Android 应用程序发布到我的 sinatra 服务 早些时候 我无法读取 sinatra 服务上的参数 但是 在我将内容类型设置为 x www form urlencoded 之后 我能够看到参数 但不完全是我想要的 我在
  • Android - 将 ImageView 保存到具有全分辨率图像的文件

    我将图像放入 ImageView 中 并实现了多点触控来调整 ImageView 中的图像大小和移动图像 现在我需要将调整大小的图像保存到图像文件中 我已经尝试过 getDrawingCache 但该图像具有 ImageView 的大小 我
  • SharedFlow 和 StateFlow 的主要区别

    两者有什么区别共享流 and 状态流 以及如何使用这些MVI建筑学 使用简单更好吗Flow或者这些作为状态和事件 Flow 是冷的 意味着它仅在收集数据时才发出数据 另外Flow不能保存数据 可以把它看成是水在里面流动的管道 Flow中的数
  • Android:有没有办法以毫安为单位获取设备的电池容量?

    我想获取设备的电池容量来进行一些电池消耗计算 是否可以以某种方式获取它 例如 三星 Galaxy Note 2 的电池容量为 3100mAh 谢谢你的帮助 知道了 在 SDK 中无法直接找到任何内容 但可以使用反射来完成 这是工作代码 pu
  • 用于推送通知的设备令牌

    我正在实施推送通知服务 我需要创建一个数据库来存储 4 个移动平台的所有设备令牌 我想根据他们的平台 iOS Android BlackBerry WP7 来组织它们 但是有什么方法可以区分平台 这样如果我只想向 Android 用户发送消
  • android Accessibility-service 突然停止触发事件

    我有一个 AccessibilityService 工作正常 但由于开发过程中的某些原因它停止工作 我似乎找不到这个原因 请看一下我的代码并告诉我为什么它不起作用 public class MyServicee extends Access
  • 在webview android中加载本地html文件

    我正在尝试在 android 的 webview 中加载 html 文件的内容 但是 它给了我 网页不可用错误 如果我尝试使用谷歌或雅虎等网站 它们就会起作用 html文件位于src gt main gt assests gt index
  • 在 Android 中,如何将字符串从 Activity 传递到 Service?

    任何人都可以告诉如何将字符串或整数从活动传递到服务 我试图传递一个整数 setpossition 4 但它不需要 启动时总是需要 0 Service 我不知道为什么我不能通过使用 Service 实例从 Activity 进行操作 publ
  • 无法运行我的应用程序,要求选择 Android SDK

    今天我已经安装了Android Studio 金丝雀 1 现在我无法运行我的应用程序 将出现以下对话框 我已经通过 文件 gt 项目结构 gt Android SDK 位置 设置了正确的 SDK 位置 期待您的帮助来解决这个问题 警告对话框
  • 无法将 admob 与 firebase iOS/Android 项目链接

    我有两个帐户 A 和 B A 是在 Firebase 上托管 iOS Android unity 手机游戏的主帐户 B 用于将 admob 集成到 iOS Android 手机游戏中 我在尝试将 admob 分析链接到 Firebase 项
  • 在 Google 地图上绘制线条/路径

    我很长一段时间都在忙于寻找如何在 HelloMapView 中的地图上的两个 GPS 点之间画一条线 但没有运气 谁能告诉我该怎么做 假设我使用扩展 MapView 的 HelloMapView 我需要使用叠加层吗 如果是这样 我是否必须重

随机推荐