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

PART1

何为内存泄漏?

 

内存泄露(Memory leak),是指程序在向系统申请分配内存空间后(new),在使用完毕后未释放。

 

结果导致一直占据该内存单元,我们和程序都无法再使用该内存单元,直到程序结束,这是内存泄露。

 

PART2

JVM/ART

 

  • JVM(Java虚拟机)

 

是一个虚构出来的运行Java程序的运行时环境,是通过在实际的计算机上仿真模拟各种计算机功能的实现。

 

它具有完善的硬件架构(如处理器、堆栈、寄存器等),还具有相应的指令系统,使用JVM就是使Java程序支持与操作系统无关。

 

 

  • ART(android虚拟机)

 

 

 

PART3

内存区域分布

移动端专项测试-内存泄漏_第1张图片

 

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

 

  • 栈(stack)

 

是简单的数据结构,但在计算机中使用广泛。

 

栈最显著的特征是:LIFO(Last In, First Out, 后进先出),栈中只存放基本类型和对象的引用(不是对象)

 

  • 堆(heap)

堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。

 

JVM只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身。

 

  • 方法区(method)

 

又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。

 

PART4

内部才能泄漏原因分析

 

那么问题来了?究竟哪部分的内存会导致内存泄漏呢?

 

 

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

 

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

 

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

 

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

 

综上所述,栈(stack)可以自行清除不用的内存空间。但是如果我们不停的创建新对象,堆(heap)的内存空间就会被消耗尽。所以内存泄漏会发生在堆区。

 

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

 

PART5

垃圾回收机制

 

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

 

 

 

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

 

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

 

移动端专项测试-内存泄漏_第2张图片

 

根据上图可以知道:由于obj4没有root指向它,所以GC会释放它所占据的内存,obj7由于还有其他引用指向它,所以得不到释放(如果持有对象的引用,垃圾回收器是无法在内存中回收这个对象)

 

所以内存泄露的真因是:

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

 

PART6

内存泄漏对应用的影响

 

内存泄漏对于app没有直接危害,即使有发现内存泄漏的情况,也不一定会立即引起app崩溃,但是通过累积效应,应用会爆出各种问题:

 

 

 

PART7

实战案例

 

 

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

 

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

 

移动端专项测试-内存泄漏_第3张图片

 

操作步骤:

移动端专项测试-内存泄漏_第4张图片

1、打开App,进入到默认页面(首页),手动触发GC,记录此时的内存值;

 

移动端专项测试-内存泄漏_第5张图片

2、测试结束后,返回到默认页面,手动触发GC,同时记录此时的内存值;

 

移动端专项测试-内存泄漏_第6张图片

3、两者做比较,发现值存在较大差异,可以断言发生了内存泄漏;

 

移动端专项测试-内存泄漏_第7张图片

4、此时可以点击Dump Java Heap,收集此时的内存信息,完成之后会自动保存在后缀为hprof文件中;

 

移动端专项测试-内存泄漏_第8张图片

5、拿hprof文件做具体分析即可(可提交给开发)。

移动端专项测试-内存泄漏_第9张图片

 

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

 

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

 

移动端专项测试-内存泄漏_第10张图片

操作步骤:

移动端专项测试-内存泄漏_第11张图片

1、打开monitor.bat,链接设备;

 

移动端专项测试-内存泄漏_第12张图片

2、选择要调试的进程,打开调试App->进入到首页;

 

移动端专项测试-内存泄漏_第13张图片

3、点击Update heap->Cause GC,记录下此时data object这一栏数据;

 

移动端专项测试-内存泄漏_第14张图片

4、测试结束后,返回到默认页面,点击Cause GC,同时记录data object这一栏数据;

 

移动端专项测试-内存泄漏_第15张图片

5、前后两者做对比,发现值存在较大差异,可以断言发生了内存泄漏;

 

移动端专项测试-内存泄漏_第16张图片

6、此时点击Dump HPROF file按钮,获取保存有内存信息的hprof文件;

 

移动端专项测试-内存泄漏_第17张图片

7、拿hprof文件做具体分析即可(可提交给开发)。

移动端专项测试-内存泄漏_第18张图片

 

  • LeakCanary+Monkey(推荐)

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

 

 

在测试过程中,我们可以结合Monkey健壮性测试工具自动化执行,测试结束后,LeakCanary自动展示内存泄漏问题:

 

移动端专项测试-内存泄漏_第19张图片

 

你可能感兴趣的:(移动端专项测试-内存泄漏)