从功能上来看,一个高级语言虚拟机主要分为两部分,一个是解释器部分,用来运行高级语言编译生成的ByteCode;还有一部分则是Runtime运行时,用来负责运行时的内存空间开辟、管理等等。

JAVA虚拟机、Dalvik虚拟机和ART虚拟机简要对比- https://blog.csdn.net/jason0539/article/details/50440669

Dalvik虚拟机,嵌入式虚拟机。

> Dalvik虚拟机和JVM有什么区别:
     Dalvik 基于寄存器,而 JVM 基于栈。基于寄存器的虚拟机对于更大的程序来说,在它们编译的时候,花费的时间更短。
 Dalvik执行.dex格式的字节码,而JVM执行.class格式的字节码。

   JVM虚拟机的多线程是通过线程切换并分配执行时间,同时一个内核在任一时刻只处理一条线程的指令 。
   虚拟机栈和堆是线程共享的数据区;方法区、本地方法栈和程序计数器是线程所不能访问到的数据区。
   其中数据访问的方式有两种:一种是句柄形式,引用指向句柄,句柄包含对象地址和对象类型;一种是指针,直接存储对象地址,以句柄少一步,所以访问也会快一些,而HotSpot就是用这种;前者也有一定优化,值发生改变时,引用不用变,后者要改变指针才行。
   内存异常有两种表现,一种叫OutOfMemoryError(内存溢出),请求的虚拟机扩展栈已无足够空间,分配给新对象,典型的标记-清理算法容易产品这种情况,另一种叫StackOverflowError(内存泄露),请求的栈深度超过虚拟机所允许 ,例如下标超过数据大小,一般线程不同步会引起这种状况的产生。
    算法复杂度分为时间复杂度和空间复杂度。其作用: 时间复杂度是指执行算法所需要的计算工作量;而空间复杂度是指执行这个算法所需要的内存空间。(算法的复杂性体现在运行该算法时的计算机所需资源的多少上,计算机资源最重要的是时间和空间(即寄存器)资源,因此复杂度分为时间和空间复杂度。)。

-- Dalvik 虚拟机和 Sun JVM 在架构和执行方面有什么本质区别?- https://www.zhihu.com/question/20207106
 JVM: .java -> javac -> .class -> jar -> .jar , 架构: 堆和栈的架构.
 DVM: .java -> javac -> .class -> dx.bat -> .dex , 架构: 寄存器(cpu上的一块高速缓存)。

-- Dalvik与JVM的最大差别在于,前者基于寄存器架构(句柄引用),后者基于栈架构(指针引用),也就是说前者处理速度更快。另外后者采用JIT的编译方式即时编译-也叫热加载,适用于J2EE;而前者采用AOT的加载方式,提前编译,虽然加载时间变长,但运行过程流畅,适用于J2ME(Java Platform,Micro Edition),而iOS也是同样的原理。

> ART与Dalvik的区别, ART虚拟机的兼容性问题
为什么Android4.4采用ART取代Dalvik非常重要?-- http://mobile.51cto.com/news-417703.htm
Dalvik和ART运行时环境的区别-- http://blog.csdn.net/watermusicyes/article/details/50526814
Dalvik和ART的区别-- http://www.cnblogs.com/shaweng/p/3811461.html
art和dalvik的区别?-- http://www.zhihu.com/question/29406156

 重点:Dalvik 使用 JIT(Just in time)编译而 ART 使用 AOT(Ahead of time)编译。
在 Android 中,Java 类被转换成 DEX 字节码。DEX 字节码通过 ART 或者 Dalvik runtime 转换成机器码。这里DEX 字节码和设备架构无关。

Dalvik 是一个基于 JIT(Just in time)编译的引擎。使用 Dalvik 存在一些缺点,所以从 Android 4.4(Kitkat)开始引入了 ART 作为运行时,从 Android 5.0(Lollipop)开始 ART 就全面取代了Dalvik。Android 7.0 向 ART 中添加了一个 just-in-time(JIT)编译器,这样就可以在应用运行时持续的提高其性能。

  Android Runtime(缩写为ART),在Android 5.0及后续Android版本中作为正式的运行时库取代了以往的Dalvik虚拟机。ART能够把应用程序的字节码转换为机器码,是Android所使用的一种新的虚拟机。

  -- ART与Dalvik的区别:
  Dalvik采用的是Android 2.2 加入的JIT技术,字节码都需要通过即时编译器(just in time ,JIT)转换为机器码,这会拖慢应用的运行效率;
  ART采用Ahead-of-time(AOT)技术,应用在第一次安装的时候,字节码就会预先编译成机器码,这个过程叫做预编译。ART同时也改善了性能、垃圾回收(Garbage Collection)、应用程序除错以及性能分析。但是请注意,运行时内存占用空间较少同样意味着编译二进制需要更高的存储。

  ART模式相比原来的Dalvik,会在安装APK的时候,使用Android系统自带的dex2oat工具把APK里面的.dex文件转化成OAT文件,OAT文件是一种Android私有ELF文件格式,它不仅包含有从DEX文件翻译而来的本地机器指令,还包含有原来的DEX文件内容。这使得我们无需重新编译原有的APK就可以让它正常地在ART里面运行,也就是我们不需要改变原来的APK编程接口。ART模式的系统里,同样存在DexClassLoader类,包名路径也没变,只不过它的具体实现与原来的有所不同,但是接口是一致的。实际上,ART运行时就是和Dalvik虚拟机一样,实现了一套完全兼容Java虚拟机的接口。

 ART和Dalvik都是使用paging和memory-mapping(mmapping)来管理内存的. 这就意味着, 任何被分配的内存都会持续存在, 唯一的释放这块内存的方式就是释放对象引用(让对象GC Root不可达), 故而让GC程序来回收内存.
Memory-mapped_file管理内存- https://en.wikipedia.org/wiki/Memory-mapped_file
paging管理内存- https://en.wikipedia.org/wiki/Paging

-- Dalvik 基于寄存器,而 JVM 基于栈。基于寄存器的虚拟机对于编译后变大的程序来说,在它们执行的时候,花费的时间更短。Dalvik和Java运行环境的区别:
 1.Dalvik主要是完成对象生命周期管理,堆栈管理,线程管理,安全和异常管理,以及垃圾回收等等重要功能。
 2.Dalvik负责进程隔离和线程管理,每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。
 3.不同于Java虚拟机运行java字节码,Dalvik虚拟机运行的是其专有的文件格式Dex
 4.dex文件格式可以减少整体文件尺寸,提高I/o操作的类查找速度。
 5.odex是为了在运行过程中进一步提高性能,对dex文件的进一步优化。
 6.所有的Android应用的线程都对应一个Linux线程,虚拟机因而可以更多的依赖操作系统的线程调度和管理机制
 7.有一个特殊的虚拟机进程Zygote,他是虚拟机实例的孵化器。它在系统启动的时候就会产生,它会完成虚拟机的初始化,库的加载,预制类库和初始化的操作。如果系统需要一个新的虚拟机实例,它会迅速复制自身,以最快的数据提供给系统。对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域。
 8.Dalvik是由Dan Bornstein编写的,名字来源于他的祖先曾经居住过名叫Dalvík的小渔村,村子位于冰岛.

  许多GC实现都是在对象开头的地方留一小块空间给GC标记用。Dalvik VM则不同,在进行GC的时候会单独申请一块空间,以位图的形式来保存整个堆上的对象的标记,在GC结束后就释放该空间。 
  dalvik是执行的时候编译+运行,安装比较快,开启应用比较慢,应用占用空间小;ART是安装的时候就编译好了,执行的时候直接就可以运行的,安装慢,开启应用快,占用空间大。用个比喻来说就是,骑自行车:dalvik 是已经折叠起来的自行车,每次骑都要先组装自行车才能骑;ART 是已经组装好的自行车,每次骑直接上车就能走人效率高在开启的时候,运行中的速度是差不多的。

-- ART和Dalvik区别
Dalvik:
Dalvik是Google公司自己设计用于Android平台的Java虚拟机
.dex格式是专为Dalvik应用设计的一种压缩格式,工作在寄存器
Dalvik经过优化,允许在有限的内存中同时运行多个虚拟机的实例,并且每一个Dalvik应用作为独立的Linux进程执行
独立的进程可以防止在虚拟机崩溃的时候所有程序都被关闭

ART:
Dalvik是依靠一个Just-In-Time(JIT)编译器去解释字节码,开发者编译后的应用代码需要通过一个解释器在用户的设备上运行,并不高效
ART在应用安装的时候就预编译字节码到机器语言,这一机制叫Ahead-Of-Time(AOT)编译,在移除解释代码这一过程后,应用程序执行将更有效率,启动更快
ART优点:1.系统性能的显著提升应用启动更快、2. 运行更快、3. 体验更流畅、触感反馈更及时、4. 更长的电池续航能力支持更低的硬件
ART缺点:1. 更大的存储空间占用、2. 可能会增加10%-20%更长的应用安装时间

区别:
ART:Ahead of Time  ,Dalvik: Just in Time
ART上应用启动快,运行快,但是耗费更多存储空间,安装时间长,总的来说ART的功效就是”空间换时间”

> Dalvik,Android虚拟机
虚拟机JIT的实现原理的简要介绍- http://blog.reverberate.org/2012/12/hello-jit-world-joy-of-simple-jits.html
Dalvik虚拟机- http://blog.csdn.net/jiazhijun/article/category/1363536
ART深度探索开篇:从Method Hook谈起- http://weishu.me/2017/03/20/dive-into-art-hello-world/

  Dalvik虚拟机的功能可以分为以下几部分:
1、进程管理:每个虚拟机都有一个进程,依赖于Zygote机制实现
2、Zygote进程管理:会fork出来一个子Zygote进程,一个SystemServer进程,一个非Zygote进程的Speciallize进程
3、类加载:先加载所有类库,然后加载字节码,放入类数据结构,供类解释器执行,如果有关联的超类、接口等也一并加载
4、内存管理:使用新老生代结合的方式,使用复制+标记-清除的算法
4、本地接口:JNI
5、反射机制:通过类结构的加载,查看、调用、修改类中的方法和属性
6、解释器:负责执行Dex字节码
7、即时编译:JIT

  Dalvik是以前的,ART是Android 4.4的时候发布的,因为Dalvik是应用运行的时候进行编译,而ART是全部编译完了再运行,效率要高很多。
  Dalvik编译的原理在于:开发者编译项目成dex,在安装时转成odex,减少了JIT时再进行字节码校验等工作;
  而ART在Android4.4版本出现,相比较Dalvik的优势在于,直接将dex编译成可执行的机器码,这样加速App的运行,减少电量的消耗,用户体验更加流畅;当然劣势也是有的,App安装时比较慢,缓存文件变大;较之iOS一次开发者编译,即在用户手机运行有先天的弊端,优势在于Android热修复和动态加载方便,而IOS相对则比较古板。

深入理解Dalvik字节码指令及Smali文件- http://blog.csdn.net/dd864140130/article/details/52076515
 深入理解Android(三):Xposed详解-- http://www.infoq.com/cn/articles/android-in-depth-xposed?utm_source=articles_about_android-in-depth&utm_medium=link&utm_campaign=android-in-depth
 深入理解Android(二):Java虚拟机Dalvik-- http://www.infoq.com/cn/articles/android-in-depth-dalvik?utm_source=articles_about_android-in-depth&utm_medium=link&utm_campaign=android-in-depth
 深入理解Android(一):Gradle详解-- http://www.infoq.com/cn/articles/android-in-depth-gradle?utm_source=articles_about_android-in-depth&utm_medium=link&utm_campaign=android-in-depth

 -- Android从ClassLoader派生出了两个类:DexClassLoader和PathClassLoader。DexClassLoader和PathClassLoader的父类是ClassLoader.
  因此DexClassLoader和PathClassLoader都属于符合双亲委派模型的类加载器(因为它们没有重载loadClass方法)。也就是说,它们在加载一个类之前,回去检查自己以及自己以上的类加载器是否已经加载了这个类。如果已经加载过了,就会直接将之返回,而不会重复加载。
  DexClassLoader和PathClassLoader其实都是通过DexFile这个类来实现类加载的。这里需要顺便提一下的是,Dalvik虚拟机识别的是dex文件,而不是class文件。因此,我们供类加载的文件也只能是dex文件,或者包含有dex文件的.apk或.jar文件。
  PathClassLoader是通过构造函数new DexFile(path)来产生DexFile对象的;而DexClassLoader则是通过其静态方法loadDex(path, outpath, 0)得到DexFile对象。这两者的区别在于DexClassLoader需要提供一个可写的outpath路径,用来释放.apk包或者.jar包中的dex文件。换个说法来说,就是PathClassLoader不能主动从zip包中释放出dex,因此只支持直接操作dex格式文件,或者已经安装的apk(因为已经安装的apk在cache中存在缓存的dex文件)。而DexClassLoader可以支持.apk、.jar和.dex文件,并且会在指定的outpath路径释放出dex文件。
  dx --dex --output=dynamic_temp.jar dynamic.jar,这样就生成了dynamic_temp.jar,这个jar和dynamic.jar有什么区别呢?
  其实这条命令主要做的工作是:首先将dynamic.jar编译成dynamic.dex文件(Android虚拟机认识的字节码文件),然后再将dynamic.dex文件压缩成dynamic_temp.jar,当然你也可以压缩成.zip格式的,或者直接编译成.apk文件。

-- 插件开发的过程中DexClassLoader和PathClassLoader这两个类加载器了是很重要的,但是他们也是有区别的,而且我们也知道PathClassLoader是Android应用中的默认加载器。他们的区别是:
  DexClassLoader可以加载任何路径的apk/dex/jar
  PathClassLoader只能加载/data/app中的apk,也就是已经安装到手机中的apk。这个也是PathClassLoader作为默认的类加载器的原因,因为一般程序都是安装了,在打开,这时候PathClassLoader就去加载指定的apk(解压成dex,然后在优化成odex)就可以了。

-- ClassLoader双亲委派机制能很好地解决类加载的统一性问题。对一个 Class 对象来说,如果类加载器不同,即便是同一个字节码文件,生成的 Class 对象也是不等的。也就是说,类加载器相当于 Class 对象的一个命名空间。双亲委派机制则保证了基类都由相同的类加载器加载,这样就避免了同一个字节码文件被多次加载生成不同的 Class 对象的问题。但双亲委派机制仅仅是Java 规范所推荐的一种实现方式,它并不是强制性的要求。近年来,很多热部署的技术都已不遵循这一规则,如 OSGi 技术就采用了一种网状的结构,而非双亲委派机制。

-- Dalvik的类加载器:
import android.app.Activity;  
import android.content.Context;  
import android.os.Bundle;  
import android.util.Log;  
import android.widget.ListView;  
  
public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
          
        Log.i("DEMO", "Context的类加载加载器:"+Context.class.getClassLoader());  
        Log.i("DEMO", "ListView的类加载器:"+ListView.class.getClassLoader());  
        Log.i("DEMO", "应用程序默认加载器:"+getClassLoader());  
        Log.i("DEMO", "系统类加载器:"+ClassLoader.getSystemClassLoader());  
        Log.i("DEMO", "系统类加载器和Context的类加载器是否相等:"+(Context.class.getClassLoader()==ClassLoader.getSystemClassLoader()));  
         Log.i("DEMO", "系统类加载器和应用程序默认加载器是否相等:"+(getClassLoader()==ClassLoader.getSystemClassLoader()));   
        Log.i("DEMO","打印应用程序默认加载器的委派机制:");  
        ClassLoader classLoader = getClassLoader();  
        while(classLoader != null){  
            Log.i("DEMO", "类加载器:"+classLoader);  
            classLoader = classLoader.getParent();  
        }    
        Log.i("DEMO","打印系统加载器的委派机制:");  
        classLoader = ClassLoader.getSystemClassLoader();  
        while(classLoader != null){  
            Log.i("DEMO", "类加载器:"+classLoader);  
            classLoader = classLoader.getParent();  
        }       
    }  

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐