Android性能:内存篇之Android虚拟机

本文详细探讨了Android系统中的Dalvik和ART虚拟机,包括两者内存分配、GC机制及其区别。Dalvik运行.dex文件,采用解释器执行,而ART自Android 5.0起成为默认虚拟机,提供了更高效的内存管理和性能。

Android性能:内存篇之Android虚拟机

《Android性能:内存篇之虚拟机概论》中我们已经初步了解了JVM的结构基础与内存空间,,但是Android系统中的java虚拟机毕竟不是使用JVM,而是Delvik(Android系统5.0之前版本)与ART(Android4.4及之后版本),在《Android性能:内存篇之内存回收》对内存回收有了深入的了解,接下来我们详细聊聊Android虚拟机的内存回收机制及与虚拟机之间的关联。

一、Dalvik虚拟机

1. Delvik

Dalvik是Google公司自己设计用于Android平台的Java虚拟机,但它运行的不是 .class文件(java字节码),而是.dex文件(dex字节码)。 Dalvik虚拟机包含有一个解释器,用来执行dex字节码,.dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。Dalvik 经过优化,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik 应用作为一个独立的Linux 进程执行。

主流的大部分Davik采取的都是标注与清理(Mark and Sweep)回收算法,也有实现了拷贝GC算法的(具体算法看《Android性能:内存篇之内存回收》)。

2. 内存分配

Delvik中,内存分配实际上是对堆的分配和释放。当一个 Android 程序启动,应用进程都是从一个叫做 Zygote 的进程衍生出来,系统启动 Zygote 进程后,为了启动一个新的应用程序进程,系统会衍生 Zygote 进程生成一个新的进程,然后在新的进程中加载并运行应用程序的代码。其中,大多数的 RAM pages 被用来分配给Framework 代码,同时促使 RAM 资源能够在应用所有进程之间共享。

为了整个系统的内存控制需要,系统会为每一个应用程序都设置一个堆的限制阈值,整个阈值在不同设备上会因为 RAM 大小不同而有所差异。如果应用占用内存空间已经接近整个阈值时,再尝试分配内存的话,就很容易引起内存溢出的错误。

关于堆的大小,有三个重要数值:Java堆的起始大小(Starting Size)、最大值(Maximum Size)和增长上限值(Growth Limit)。

-dalvik.vm.heapstartsize        
    
-dalvik.vm.heapgrowthlimit       

-dalvik.vm.heapsize 
  • Starting Size : 堆的起始大小,Dalvik虚拟机启动的时候,会先分配一块初始的堆内存给虚拟机使用,这个数值越大,应用启动越流畅,但是系统RAM也消耗越快(一些较大的应用需要扩张这个堆,从而引发GC和堆调整的策略,因此也会使应用反应更慢)。
  • Growth Limit:受控情况下的极限堆(仅仅针对dalvik堆,不包括native堆)大小,是系统给每一个程序的最大堆上限,dvm heap是可增长的,但是正常情况下dvm heap的大小是不会超过dalvik.vm.heapgrowthlimit的值,超过这个上限,程序就会OOM。
  • Maximum Size:不受控情况下的最大堆内存大小,起始就是我们在用largeheap属性的时候,可以从系统获取的最大堆大小,这个就是堆的最大值。不管它是不是受控的。这个值会影响非受控应用的dalvikheap size。一旦dalvik heap size超过这个值,直接引发oom。

同时除了上面的这个三个指标外,还有几个指标也是值得我们关注的,那就是堆最小空闲值(Min Free)、堆最大空闲值(Max Free)和堆目标利用率(Target Utilization)。

当我们尝试手动去生成一些几百K的对象,试图去扩大可用堆大小的时候,会导致频繁的GC,因为这些对象的分配会导致GC,而GC后会让堆内存回到合适的比例,而我们使用的局部变量很快会被回收理论上存活对象还是那么多,我们的堆大小也会缩减回来无法达到扩充的目的。

3. 对象的分配和GC的步骤
在这里插入图片描述
大概步骤是:1. 分配内存;2.内存分配失败,则执行GC(但是不回收Soft的引用);3.分配内存;4.不够?扩大Growth Limit,再次分配内存;5.还不够?指定堆大小到最大,继续GC(释放Soft的引用);6.OOM之前再释放一次,实在不行就OOM吧

二、ART虚拟机

1. ART

ART(Android Runtime)是 Android 上的应用和部分系统服务使用的托管式运行时,4.4开始使用,从Android 5.0(Lollipop)开始,ART就彻底代替了原先的Dalvik,成为Android系统上新的虚拟机,作为运行时的 ART 可执行 Dalvik 可执行文件并遵循 Dex 字节码规范。
Art在GC上不像Dalvik仅有一种回收算法,Art在不同的情况下会选择不同的回收算法,比如Alloc内存不够的时候会采用非并发GC,而在Alloc后发现内存达到一定阀值的时候又会触发并发GC。

2. 内存分配

ART运行时内部使用的Java堆的主要组成包括Image Space、Zygote Space、Allocation Space和Large Object Space四个Space,Image Space用来存在一些预加载的类, Zygote Space和Allocation Space与Dalvik虚拟机垃圾收集机制中的Zygote堆和Active堆的作用是一样的,Large Object Space就是一些离散地址的集合,用来分配一些大对象从而提高了GC的管理效率和整体性能。

3. 对象的分配和GC的步骤

与Delvik基本一致,看上图即可。

三、JVM、Delvik、ART的比较

JVMDelvik
基于栈(需要更多指令,移植性好,性能更低)基于寄存器(需要更少指令,移植性稍差,性能更佳)
基于不同的硬件提供统一的Java应用运行时环境采用预加载,并不提供统一的环境
执行的是class文件执行的是dex文件(由class文件转化),占用空间更小
*为简化翻译,常量池只使用32位索引
DelvikART
安装时是dex字节码,运行需要即时 (JIT1) 编译器翻译成机器码再运行采用了AOT2预编译技术,安装时直接编译成机器码(Android 7.0 中,ART组合使用了AOT和JIT)
占用空间小,启动运行慢占用空间大,安装时间稍长,启动运行更快,节约CPU资源
GC的停顿为2次GC的停顿为1次(并发GC)
回收器的总GC时间略长回收器的总GC时间更短
GC次数较少优化了垃圾回收的工效,能够更加及时地进行并行垃圾回收

总的来说,ART在GC上做的比Dalvik好太多了,不光是GC的效率,减少pause时间,而且还在内存分配上对大内存的有单独的分配区域,同时还能有算法在后台做内存整理,减少内存碎片。对于开发者来说ART下我们基本可以避免很多类似gc导致的卡顿问题了。另外根据谷歌自己的数据来看,Art相对Dalvik内存分配的效率提高了10倍,GC的效率提高了2-3倍。


  1. JIT:Just in Time,即时编译 ↩︎

  2. AOT:Ahead-Of-Time,预编译 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值