一、Java虚拟机JVM类加载过程
JVM(虚拟机)把描述类的数据的字节码.Class文件加载到内存,并对数据进行校正、转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制。
JVM三种预定义类型类加载器
- 启动类加载器(Bootstrap ClassLoader):负责加载JAVA_HOME\lib目录中并且能被虚拟机识别的类库到JVM内存中,如果名称不符合的类库即使放在lib目录中也不会被加载。该类加载器无法被Java程序直接引用。
- 扩展类加载器(Extension ClassLoader):该加载器主要是负责加载JAVA_HOME\lib\,该加载器都可以被开发者直接使用。
- 应用程序类加载器(Application ClassLoader):该类加载器也成为系统类加载器,它负责加载用户类路径(Classpath)上所指定的类库,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
对于上面三种类加载器,其中启动类加载器(Bootstrap ClassLoader)使用C++语言实现,属于虚拟机自身的一部分,不是ClassLoader的子类。所有其他的类加载器,这些类加载器是由Java语言实现,独立于JVM外部,并且全部继承自抽象类lava.lang.ClassLoader。
步骤
- 加载(查找并加载类的二进制数据)
由类加载器执行,查找字节码,并创建一个Class对象(只是创建) - 链接
验证字节码,为静态域分配存储空间(只是分配,并不初始化该存储空间),解析该类创建所需要的对其它类的应用 - 初始化
首先执行静态初始化块static{},初始化静态变量,执行静态方法(如构造方法)
初始化过程会被触发:
—— 创建类的实例
—— 访问某个类或者接口的静态变量,或者对该静态变量赋值(如果访问静态编译时常量(即编译时可以确定值的常量)不会导致类的初始化)
—— 调用类的静态方法
—— 反射(Class.forName(xxx.xxx.xxx))
—— 初始化一个类的子类(相当于对父类的主动使用),不过直接通过子类引用父类元素,不会引起子类的初始化
—— Java虚拟机被标明为启动类的类(包含main方法的)
二、Android虚拟机Dalvik/ART VM加载过程
Dalvik/ART VM 虚拟机加载类和资源也是要用到ClassLoader,不过Jvm通过ClassLoader加载的class字节码,而Dalvik/ART VM通过ClassLoader加载则是dex。
Android的类加载器分为PathClassLoader和DexClassLoader两种,两者都继承自BaseDexClassLoader,BaseDexClassLoader继承ClassLoader。
PathClassLoader
:用来加载系统类和应用类。支持加载DEX或者已经安装的APK(因为存在缓存的DEX)。
DexClassLoader
:用来加载jar、apk、dex文件(加载jar、apk也是最终抽取里面的Dex文件进行加载)。也可以从SD卡进行加载。
三、JVM 与 Dalvik 与 ART VM
JVM虚拟机
执行的是class文件;
只存在一个;
基于栈(内存);
Dalvik虚拟机(DVM)
执行的是dex字节码 (运行时动态地将执行频率很高的dex字节码翻译成本地机器码);
可同时存在多个(每个android app对应着一个Dalvik虚拟机实例);
基于寄存器;
android5.0后虚拟机由dalvik替换为ART(Android Runtime),在安装应用的时候,dex中的字节码将被编译成本地机器码,之后每次打开应用,执行的都是本地机器码。
ART虚拟机
执行的是本地机器码 (安装应用的时候,dex中的字节码将被编译成本地机器码,之后每次打开app,执行的都是本地机器码)
ART对比dalvik:
(JIT:Just In Time,即时编译技术;AOT:Ahead Of Time,预编译技术。)
1、Dalvik运行时使用JIT将字节码转换成机器码,执行效率低;
2、ART采用AOT预编译技术,执行效率更快,应用启动更快、运行更快、体验更流畅、触感反馈更及时;
3、ART预编译减少了 CPU 的使用频率,降低了能耗,提高了续航
4、ART会占用更多的安装时间和存储空间 (因为预编译..)
参考资料:
Android热更新一:JAVA的类加载机制
从Java到android:类的加载机制
(部分内容参考于网络,如有不妥,请联系删除~)