美文网首页Android技术知识
Android虚拟机与类加载机制

Android虚拟机与类加载机制

作者: 搬砖小老弟 | 来源:发表于2022-05-25 14:42 被阅读0次

    作者:木水Code
    转载地址:https://juejin.cn/post/7101320493327712292

    JVM和Dalvik/ART

    Android应用程序运行在Dalvik/ART虚拟机,并且每一个应用程序对应有一个单独的Dalvik虚拟机实例。Dalvik虚拟机实则也算是一个Java虚拟机,只不过它执行的不是class文件,而是dex文件。Dalvik虚拟机与Java虚拟机共享有差不多的特性,差别在于两者执行的指令集是不一样的,前者的指令集是基本寄存器的,而后者的指令集是基于堆栈的。

    基于栈的虚拟机

    对于基于栈的虚拟机来说,每一个运行时的线程,都有一个独立的栈。栈中记录了方法调用的历史,每有一次方法调用,栈中便会多一个栈桢。最顶部的栈桢称作当前栈桢,其代表着当前执行的方法。基于栈的虚拟机通过操作数栈进行所有操作。

    public class Demo {
        public static void test() {
            int a = 1;
            int b = 2;
            int c = a + b;
        }
    }
    

    使用javap -c xxx.class进行反编译,查看字节码指令:

    • iconst_1:将int类型常量a压入操作数栈
    • istore_0:将int类型常量a存入局部变量0
    • iadd:执行int类型的加法操作

    执行过程如下:

    基于寄存器的虚拟机

    寄存器是CPU的组成部分。寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令、数据和位址。

    基于寄存器的虚拟机中没有操作数栈,但是有很多虚拟寄存器。其实和操作数栈相同,这些寄存器也存放在运行时栈中,本质上就是一个数组。与JVM相似,在Dalvik VM中每个线程都有自己的PC和调用栈,方法调用的活动记录以帧为单位保存在调用栈上。

    与JVM版相比,可以发现Dalvik版程序的指令数明显减少了,数据移动次数也明显减少了。

    ART和Dalvik

    Dalvik虚拟机执行的是dex字节码,解释执行。 从Android 2.2版本开始,支持JIT即时编译(Just In Time)在程序运行的过程中进行选择热点代码(经常执行的代码)进行编译或者优化。而ART(Android Runtime) 是在 Android 4.4 中引入的一个开发者选项,也是 Android 5.0 及更高版本的默认 Android 运行时。ART虚拟机执行的是本地机器码。 Android的运行时从Dalvik虚拟机替换成ART虚拟机,并不要求开发者将自己的应用直接编译成目标机器码,APK仍然是一个包含dex字节码的文件。

    dex2aot

    Dalvik下应用在安装的过程,会执行一次优化,将dex字节码进行优化生成odex文件。而Art下将应用的dex字节码翻译成本地机器码的最恰当AOT时机也就发生在应用安装的时候。ART 引入了预先编译机制**(Ahead Of Time),在安装时,ART 使用设备自带的 dex2oat 工具来编译应用,dex中的字节码将被编译成本地机器码。

    Android N(7.0)的运作方式

    ART 使用预先 (AOT) 编译,并且从 Android N混合使用AOT编译,解释和JIT。

    1、最初安装应用时不进行任何 AOT 编译(安装又快了),运行过程中解释执行,对经常执行的方法进行JIT,经过 JIT 编译的方法将会记录到Profile配置文件中。

    2、当设备闲置和充电时,编译守护进程会运行,根据Profile文件对常用代码进行 AOT 编译。待下次运行时直接使用。

    类加载机制

    双亲委派机制

    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException
        {
                //检查类是否已经被加载过
                Class<?> c = findLoadedClass(name);
                if (c == null) {
                    //没被加载过,就去加载该类
                    try {
                        if (parent != null) {
                            //parent不为null,则调用parent的loadClass去加载
                            c = parent.loadClass(name, false);
                        } else {
                            //parent为null,则调用BootClassLoader去加载类(从Framework中找)
                            c = findBootstrapClassOrNull(name);
                        }
                    } catch (ClassNotFoundException e) {
                        // ClassNotFoundException thrown if class not found
                        // from the non-null parent class loader
                    }
    
                    if (c == null) {
                        //如果还是找不到,就调用findClass自己去找(从app中找)
                        c = findClass(name);
                    }
                }
                return c;
        }
    

    某个类加载器在加载类时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务或者没有父类加载器时,才自己去加载。

    好处:

    1、避免重复加载,当父加载器已经加载了该类的时候,就没有必要子ClassLoader再加载一次。

    2、安全性考虑,防止核心API库被随意篡改。

    类加载过程

    相关文章

      网友评论

        本文标题:Android虚拟机与类加载机制

        本文链接:https://www.haomeiwen.com/subject/rnbeprtx.html