移动端专项测试-内存泄漏

何为内存泄漏?

内存泄露(Memory leak),是指程序在向系统申请分配内存空间后(new),在使用完毕后未释放。结果致使一直占据该内存单元,咱们和程序都没法再使用该内存单元,直到程序结束,这是内存泄露。java

JVM/ART

JVM(Java虚拟机)
是一个虚构出来的运行Java程序的运行时环境,是经过在实际的计算机上仿真模拟各类计算机功能的实现。它具备完善的硬件架构(如处理器、堆栈、寄存器等),还具备相应的指令系统,使用JVM就是使Java程序支持与操做系统无关。
理论上在任何操做系统中,只要有对应的JVM,便可运行Java程序。android

ART(android虚拟机)
是在Android系统上运行Android程序的虚拟机,其指令集是基于寄存器架构的,执行特有的文件格式-dex字节码来完成对象生命周期管理、堆栈管理、线程管理、安全异常管理、垃圾回收等重要功能。
其实ART就是在JVM基础上专门为android移动设备定制的一套虚拟机方案。数组

内存区域分布

JAVA是在JVM所虚拟出的内存环境中运行的,JVM的内存可分为三个区:
堆(heap)、栈(stack)和方法区(method)。android-studio

栈(stack)
是简单的数据结构,但在计算机中使用普遍。栈最显著的特征是:LIFO(Last In, First Out, 后进先出),栈中只存放基本类型和对象的引用(不是对象)安全

堆(heap)
堆内存用于存放由new建立的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。JVM只有一个堆区(heap)被全部线程共享,堆中不存放基本类型和对象引用,只存放对象自己。数据结构

方法区(method)
又叫静态区,跟堆同样,被全部的线程共享。方法区包含全部的class和static变量架构

内存泄漏缘由分析

那么问题来了?究竟哪部分的内存会致使内存泄漏呢?
在JAVA中JVM的栈记录了方法的调用,每一个线程拥有一个栈。app

在线程的运行过程中,执行到一个新的方法调用,就在栈中增长一个内存单元,即帧(frame)。在frame中,保存有该方法调用的参数、局部变量和返回地址。jvm

然而JAVA中的局部变量只能是基本类型变量(int),或者对象的引用。因此在栈中只存放基本类型变量和对象的引用。引用的对象保存在堆中。工具

当某方法运行结束时,该方法对应的frame将会从栈中删除,frame中全部局部变量和参数所占有的空间也随之释放。 线程回到原方法继续执行,当全部的栈都清空的时候,程序也就随之运行结束。

而对于堆内存,堆存放着普通变量。在JAVA中堆内存不会随着方法的结束而清空,因此在方法中定义了局部变量,在方法结束后变量依然存活在堆中。

综上所述,栈(stack)能够自行清除不用的内存空间。可是若是咱们不停的建立新对象,堆(heap)的内存空间就会被消耗尽。因此内存泄漏会发生在堆区。

JAVA引入了垃圾回收(garbage collection,简称GC)去处理堆内存的回收。

垃圾回收机制

垃圾回收(garbage collection,简称GC)能够自动清空堆中再也不使用的对象。

在JAVA中对象是经过引用使用的。若是再没有引用指向该对象,那么该对象就无从处理或调用该对象,这样的对象称为不可到达(unreachable)。

垃圾回收用于释放不可到达的对象所占据的内存。

根据上图能够知道:因为obj4没有root指向它,因此GC会释放它所占据的内存,obj7因为还有其余引用指向它,因此得不到释放(若是持有对象的引用,垃圾回收器是没法在内存中回收这个对象)

因此内存泄露的真因是:

持有对象的强引用,且没有及时释放,进而形成内存单元一直被占用,浪费空间,形成内存溢出

内存泄漏对应用的影响

内存泄漏对于app没有直接危害,即便有发现内存泄漏的状况,也不必定会当即引发app崩溃,可是经过累积效应,应用会爆出各类问题:
一、内存得不到释放,慢慢的会形成app内存溢出,致使崩溃
二、内存泄漏同时可能会触发系统频繁GC,发生内存抖动,会致使系统性能问题(卡顿不流畅)

测试场景选择

  • 新页面打开
  • 横竖屏切换
  • 滑动屏幕

测试方式

有源码+Android Studio环境,借助Profiler

操做步骤:

  • 打开App,进入到默认页面(首页),手动触发GC,记录此时的内存值
  • 测试结束后,返回到默认页面,手动触发GC,同时记录此时的内存值
  • 二者作比较,发现值存在较大差别,能够断言发生了内存泄漏
  • 此时能够点击Dump Java Heap,收集此时的内存信息,完成以后会自动保存在后缀为hprof文件中
  • 拿hprof文件作具体分析便可(可提交给开发)

无源码,有debug版本的APK包,借助DDMS工具

DDMS是Android SDK中自带的调试工具
须要注意的是:新版本的SDK中,DDMS工具已经集成到了Android device mointor中

操做步骤:

  • 打开monitor.bat,连接设备
  • 选择要调试的进程,打开调试App->进入到首页
  • 点击Update heap->Cause GC,记录下此时data object这一栏数据
  • 测试结束后,返回到默认页面,点击Cause GC,同时记录data object这一栏数据
  • 先后二者作对比,发现值存在较大差别,能够断言发生了内存泄漏
  • 此时点击Dump HPROF file按钮,获取保存有内存信息的hprof文件
  • 拿hprof文件作具体分析便可(可提交给开发)

LeakCanary+Monkey(推荐)

LeakCanary是Square公司基于MAT开源的一个工具,用于检测Android App的内存泄漏,咱们能够经过集成LeakCanary提供的jar包到本身的项目工程中,一旦检测到内存泄漏问题,LeakCanary会自动dump内存信息,经过另一个进程分析内存泄漏信息并展现出来,能够随时发现和定位内存泄漏问题。

在测试过程当中,咱们能够结合Monkey健壮性测试工具自动化执行,测试结束后,LeakCanary自动展现内存泄漏问题:

相关文章
相关标签/搜索