Java虚拟机系列五:android虚拟机

1,374 阅读6分钟

[toc]

一.android虚拟机与hotspot虚拟机的区别

android虚拟机

  • 非标准jvm实现
  • 存储和执行dex文件
  • 采用基于寄存器的指令集
  • 指令长度为2,4,6个字节,执行指令效率高,移植性差,依赖于平台

hotspot虚拟机

  • 标准jvm实现
  • 存储和执行class文件
  • 采用基于栈的指令集
  • 指令长度为1个字节,因此具备有很好的移植性。

二. dalvik和art

1.Dalvik虚拟机

是Google等厂商合作开发的Android移动设备平台的核心组成部分之一。它可以支持已转换为.dex(即DalvikExecutable)格式的Java应用程序的运行。

2.ART虚拟机(Android Runtime)

由Google公司研发,在Android5.0及后续Android版本中作为正式的运行时库取代了以往的Dalvik虚拟机。ART能够把应用程序的字节码转换为机器码,是Android所使用的一种新的虚拟机。

3.主要不同点

Dalvik采用的是JIT技术,而ART采用Ahead-of-time(AOT)技术。ART同时也改善了性能、垃圾回收、应用程序出错以及性能分析。

android 5.0之前默认采用dalvik虚拟机,android5.0之后采用art虚拟机。

4.jit 与aot

JIT通过进行连续的性能分析(通过热点探测技术记录函数的调用频率和时长,用于确定程序哪部分需要优化。热点探测技术一般包含采样探测和方法执行计数两种。采样探测定时扫描记录每个线程栈的栈顶的方法,频率高的方法认定为热点方法;方法执行计数为每个方法的执行提供一个计数器记录方法执行次数,次数超过阈值的认定为热点方法)来优化程序代码的执行,在程序运行的过程中,Dalvik虚拟机在不断的进行将字节码编译成机器码的工作。

AOT在应用程序安装的过程中,就已经将所有的字节码重新编译成了机器码。应用程序运行过程中无需进行实时的编译工作,只需要进行直接调用。

image

jit通过工具dexopt将dex文件转化为odex文件,odex相对于dex的优化内容包含指令修改为quick指令以及将fied_idx改为用offset来定位

aot通过工具dex2oat将dex转化为elf(ExecutableAndLinkableFormat文件,它是一种类Unix操作系统上的二进制文件格式标准。

三.android虚拟机栈

1.hotspot 虚拟机栈

jvm_stack_frame

hotspot虚拟机栈中以栈结构存储了代表运行时的方法的栈帧列表,对于虚拟机栈的详细介绍参考Java虚拟机系列三: 运行时数据区解析,这里我们重点关注与android虚拟机的区别点:它通过局部变量表和操作数栈来实现局部变量的存储与计算,并返回结果。

2.dalvik 寄存器

android虚拟机栈同样存储的是一系列的栈帧,不同的是栈帧中去除了操作比较繁琐的局部变量表和操作数栈,改为采用寄存器来存储指令,局部变量以及结果信息。

dalvik_register

基于寄存器的指令更长,同时能处理的内容也更多,能有效的减少io次数。

四.android虚拟机堆

1.hotspot虚拟机堆

在Java虚拟机系列四:堆区管理中,我们分析了标准jvm的堆区结构由新生代,老年代和元数据区组成,其中新生代又区分为eden区和suvivor区,经过gc之后在不同的区中流转。

jvm_heap

2.Art虚拟机堆

Art虚拟机充分考虑移动端的数据特性,如启动需要的公共的class文件,图片等。

具体来看,art虚拟机堆由四部分组成:

image space - zygote space - allocation space - largeObject space

image

1.ImageSpace

存放boot.oat文件,它不会执行堆的gc

2.zygoteSpace

连续地址空间,匿名共享内存,进行垃圾回收,管理Zygote进程在启动过程中预加载的类和创建的各种对象资源。

3.allocation space

与传统的hotspot虚拟机堆相似,app运行过程中的对象的分配都在这里。

4.largetObject space

离散地址空间,进行垃圾回收,用来分配一些大于12K的大对象。

五.art虚拟机的gc策略

1.三种gc策略

  • Sticky GC :只回收上一次GC到本次GC之间申请的内存。
  • Partial GC:局部垃圾回收,除了ImageSpace和ZygoteSpace空间以外的其他内存垃圾。
  • Full GC: 全局垃圾回收,除了ImageSpace之外的Space的内存垃圾

2.gc的三个阶段:

阶段一:首先会进行一次轻量级的GC,完成后尝试分配。如果分配失败,则选取下一个GC策略,再进行一次轻量级GC。每次GC完成后都尝试分配,直到三种GC策略都被轮询了一遍还是不能完成分配,则进入下一阶段。 阶段二:允许堆进行增长的情况下进行对象的分配。 阶段三:进行一次允许回收软引用的GC的情况下进行对象的分配。

3.内存泄漏分析工具

  • as memory profiler : 实时内存dump (hprof文件)
  • leak canary : 自动泄漏分析工具
  • mat : 内存分析工具
  • hprof-conv : hprof转换工具,将memoryprofiler的hprof文件转化为mat能识别的文件,工具位于android/sdk/platform-tools/
  • visual vm : 可视化的vm内存实时情况
  • visual gc : visual vm的gc插件

4.内存泄漏分析方法

1. 记录需要分析的两个状态的hprof文件

这两个状态一般是怀疑泄漏的页面,或者通过leakCanary提示的泄漏页面,假设为页面A有泄漏。

打开Android studio 的 memory profiler页面 进入需要分析的页面A之前的页面Main(假定这个状态为纯净状态s1),点击capture-heap-dump存储纯净状态的hprof文件为memory-s1.hprof,进出几次A页面,并点击gc按钮,最终退出A页面回到纯净页面main,点击capture-heap-dump存储当前状态的hprof文件为memory-s2.hprof

2.将hprof转化为mat能识别的文件

执行命令得到mat-s1.hprof , mat-s2.hprof

hprof-conv memory-s1.hprof mat-s1.hprof
hprof-conv momory-s2.hprof mat-s2.hprof

3.对比 hprof文件

用mat工具导入mat-s1.hprof ,mat-s2.hprof 在mat-s1.hprof页面点击右上角的diff按钮,选择mat-s2.hprof,得到多次进入页面A之后增加的对象列表。

mat_diff

如图可以清晰看到SecondActivity增加了7个,为泄漏的对象。

重新点开mat-s2.hprof文件,这里一定要重新点开,否则会找不到持有链接的入口,找到SecondActivity,右键点击merge-shortest-Paths-to-Gc-Roots就可以得到持有SecondeActivity的实际对象。 mat-link