Android虚拟机与类加载机制详情

yizhihongxing

Android虚拟机与类加载机制

什么是Android虚拟机

Android虚拟机是为了在计算机上模拟Android系统环境,方便开发者开发和测试安卓应用程序的工具。目前Android系统所用的虚拟机主要是Dalvik和ART两种。

Dalvik虚拟机

Dalvik虚拟机是Google在Android系统中使用的Java虚拟机,它使用了一种叫做DEX的字节码文件格式。

在Android应用程序启动时,Dalvik虚拟机会按照Android的类加载机制,载入应用程序的主类,然后从该类开始解析和装载所有的类,构建出完整的类结构。在类解析和装载的过程中,Dalvik虚拟机会开辟出一个单独的内存空间,称作“堆(heap)”,用于存储所有的对象实例和数组。

类的装载过程主要分为:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)和初始化(Initialization)五个阶段。其中,验证和解析是Dalvik虚拟机独有的步骤。

ART虚拟机

ART虚拟机是在Android 5.0系统中引入的一种新的虚拟机,它使用了一种叫做ART的字节码文件格式。

和Dalvik虚拟机不同的是,ART在应用程序安装的时候就会把字节码文件预先编译为机器码,并保存到设备的存储空间中。这样,在应用程序启动时,ART直接加载机器码,而不需要在运行过程中再进行解释和编译。

这样一来,ART虚拟机虽然需要更多的存储空间,但是却可以在应用程序启动时更快地响应,并且由于避免了解释和编译字节码的过程,还可以减少应用程序运行时的功耗,从而延长设备的电池寿命。

类加载机制

Android应用程序中的类以及所有的依赖库都是通过类加载器进行加载的。

在Android系统中,类加载器主要有BootClassLoader、PathClassLoader、DexClassLoader、InMemoryDexClassLoader等几种。它们的主要区别在于它们所负责加载类的范围不同。

  • BootClassLoader

BootClassLoader是Android系统中最高级别的类加载器,用于加载Android系统核心库(如Java核心类库、C标准库等)以及一些重要的类(如ClassLoader类、String类等)。

  • PathClassLoader

PathClassLoader也是一个很重要的类加载器,它主要用于加载那些已经安装到设备中的应用程序及其依赖库。具体来说,当一个应用程序被安装到设备中时,它的apk文件会被解压,并在设备的存储空间中生成一个odex文件。在运行时,PathClassLoader会加载该应用程序的odex文件,并从中动态地解析和装载应用程序中的所有类。

  • DexClassLoader

DexClassLoader是一个动态加载类的类加载器,它可以从设备文件系统或者网络中加载一个已经存在的dex文件,并根据dex文件中的内容动态地生成对应的类。

  • InMemoryDexClassLoader

InMemoryDexClassLoader是一个加载内存中Dex文件的类加载器,它可以从内存中加载一个Dex文件,并动态地生成对应的类。和DexClassLoader类似,InMemoryDexClassLoader能够动态地加载dex文件中的类对象,但是它从内存中加载dex文件,从而避免了读写文件的性能消耗。

示例说明

下面我们来看一个示例,演示DexClassLoader的使用方法,加载设备文件系统中指定的已有dex文件。

public class MyActivity extends Activity {
    private static final String DEX_PATH = "/sdcard/MyApp/classes.dex"; // dex文件的存放路径

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 创建DexClassLoader对象
        DexClassLoader dexClassLoader = new DexClassLoader(DEX_PATH, // dex文件的路径
            getDir("dex", Context.MODE_PRIVATE).getAbsolutePath(), // dex文件解包后存放的目录
            null, // 父级类加载器,可以为null,此处没有父级类加载器
            getClassLoader()); // 指定该类加载器作为父级类加载器,以便在加载类的时候优先使用该类加载器加载

        try {
            // 加载指定类
            Class<?> cls = dexClassLoader.loadClass("com.example.MyClass");

            // 创建类的实例
            Object obj = cls.newInstance();

            // 调用类的方法
            Method method = cls.getMethod("helloWorld");
            method.invoke(obj);

        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

上述示例中,我们通过DexClassLoader来动态加载sdcard中的classes.dex文件,并且调用其中包含的指定方法。

另外,还可以使用PathClassLoader来加载设备存储中的指定类文件,下面是一个示例:

public class MyActivity extends Activity {
    private static final String CLASS_FILE_PATH = "/sdcard/MyApp/MyClass.class"; // class文件的存放路径

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 创建PathClassLoader对象
        PathClassLoader pathClassLoader = new PathClassLoader(CLASS_FILE_PATH, getClassLoader());

        try {
            // 加载指定类
            Class<?> cls = pathClassLoader.loadClass("com.example.MyClass");

            // 创建类的实例
            Object obj = cls.newInstance();

            // 调用类的方法
            Method method = cls.getMethod("helloWorld");
            method.invoke(obj);

        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

上述示例中,我们通过PathClassLoader来动态加载设备存储中的MyClass.class文件,并且调用其中包含的指定方法。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Android虚拟机与类加载机制详情 - Python技术站

(0)
上一篇 2023年6月25日
下一篇 2023年6月25日

相关文章

  • 使用Linux五年积累的一些经验技巧

    使用Linux五年积累的一些经验技巧攻略 1. 熟悉基本命令行操作 熟悉基本的命令行操作是使用Linux的关键。以下是一些常用的命令和技巧: ls:列出当前目录下的文件和文件夹。 cd:切换目录。 mkdir:创建新的文件夹。 rm:删除文件或文件夹。 cp:复制文件或文件夹。 mv:移动文件或文件夹。 grep:在文件中搜索指定的字符串。 chmod:修改…

    other 2023年8月15日
    00
  • Mysql大小写敏感的问题

    MySQL大小写敏感的问题攻略 MySQL是一个常用的关系型数据库管理系统,它在处理大小写时有一些敏感性。本攻略将详细讲解MySQL大小写敏感的问题,并提供两个示例说明。 1. MySQL的大小写敏感性 MySQL在处理标识符(如表名、列名、变量名等)时,根据配置的不同,可能会对大小写敏感或不敏感。这取决于以下两个因素: 操作系统:在某些操作系统上,文件系统…

    other 2023年8月15日
    00
  • SecureCRT如何修改配置文件夹?SecureCRT修改配置文件夹教程

    SecureCRT是一款用于SSH(Secure Shell)协议的控制台终端模拟软件,它通过提供一种安全、简单的设置来帮助用户控制远程主机并管理多个会话。在使用SecureCRT时,如果我们需要修改配置文件夹,可以按照以下步骤进行操作: 打开SecureCRT,点击菜单栏的“选项”->“全局选项”,弹出“SecureCRT全局选项”窗口。 在“Sec…

    other 2023年6月25日
    00
  • docker删除none

    什么是Docker? Docker是一种开源的容器化平台,可以帮助开发人员和系统管理员更轻松地构建、部署和运行应用程序。 什么是Docker none? 在Docker中,当容器被删除时,它们会留下一个名为“none”的镜像。这些镜像不包含任何文件,但它们会占用磁盘空间并且可能会导致Docker镜像列表变得混乱。 如何删除Docker none? 以下是在D…

    other 2023年5月7日
    00
  • MySQL数据库主从复制原理及作用分析

    MySQL数据库主从复制原理及作用分析 MySQL数据库主从复制是一种常见的数据库复制技术,用于实现数据的备份、读写分离和负载均衡。以下是一个完整的攻略,详细讲解MySQL数据库主从复制的原理及作用,并包含两个示例说明。 1. 主从复制原理 MySQL数据库主从复制基于二进制日志(Binary Log)实现。主服务器将写操作记录到二进制日志中,并将二进制日志…

    other 2023年10月19日
    00
  • 教你在react中创建自定义hooks

    当我们在开发React应用时,很多时候我们会发现需要在多个组件中使用相同的逻辑,这时候我们可以使用自定义Hook来避免代码的重复。 创建自定义Hook的步骤 创建自定义Hook的步骤非常简单: 创建一个函数, 函数名以 “use” 开头,这个函数可以接受任意参数,但是需要返回一个对象或数组作为其结果; 在任意React组件中使用这个自定义Hook。 让我们看…

    other 2023年6月25日
    00
  • C++ Date类的具体使用(构建,重载等)

    下面我来详细讲解如何使用C++ Date类。 构建Date类对象 我们可以通过Date类的构造函数来构建一个Date类的对象,Date类的构造函数有以下两种形式: // 使用默认日期构造一个Date类对象 Date(); // 使用传入的年份、月份、日期构造一个Date类对象 Date(int year, int month, int day); 示例: #…

    other 2023年6月26日
    00
  • iOS中实现检测Zoombie对象的具体方法

    iOS中实现检测Zombie对象的具体方法 什么是Zombie对象? 在iOS开发中,Zombie对象是指已经被释放(dealloc)但仍然被访问的对象。这种情况可能会导致应用崩溃或产生难以调试的Bug。为了解决这个问题,我们可以使用Xcode提供的一些工具和技术来检测和调试Zombie对象。 使用Instruments检测Zombie对象 Instrume…

    other 2023年6月28日
    00
合作推广
合作推广
分享本页
返回顶部