标签:daemon 隔离 rap 检验 pac 编译器 限制 工具 频繁
来源>https://zhuanlan.zhihu.com/p/43278214
JVM是java virtual machine(java虚拟机)的缩写,JVM是一种用于计算机设备的规范,它是一个虚构的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。
JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK)。JDK 物理存在,是 programming tools
、JRE 和 JVM 的一个集合。
JRE(Java Runtime Environment)Java 运行时环境,JRE 是物理存在的,主要由Java API 和 JVM 组成,提供了用于执行 java 应用程序最低要求的环境。
JVM是一种用于计算设备的规范,它是一个虚构的计算机的软件实现,简单的说,JVM是运行byte code字节码程序的一个容器。
JVM使用Java字节码的方式,作为Java 用户语言 和 机器语言 之间的中间语言。实现一个通用的、 机器无关 的执行平台。
基于安全方面考虑,JVM 要求在 class 文件中使用强制性的语法和约束,但任意一门语言都可以转换为被 JVM 接受的有效的 class 文件。作为一个通用的、机器无关的执行平台,任何其他语言的实现者都可将 JVM 当作他的语言产品交付媒介。
JVM 中执行过程如下: 加载代码 验证代码 执行代码 提供运行环境
JAVA 代码执行过程如下:
类加载器 负责加载程序中的类型(类和接口),并赋予唯一的名字予以标识。
JDK 默认提供的三种 ClassLoader如下:
Java中ClassLoader的加载采用了双亲委托机制,采用双亲委托机制加载类的时候采用如下的几个步骤:
小结 :双亲委托机制的核心思想分为两个步骤。其一,自底向上检查类是否已经加载;其二,自顶向下尝试加载类。
每个类装载器都有一个自己的命名空间用来保存已装载的类。当一个类装载器装载一个类时,它会通过保存在命名空间里的类全局限定名(Fully Qualified Class Name)进行搜索来检测这个类是否已经被加载了。
JVM 及 Dalvik 对类唯一的识别是 ClassLoader id + PackageName + ClassName,所以一个运行程序中是有可能存在两个包名和类名完全一致的类的。并且如果这两个”类”不是由一个 ClassLoader 加载,是无法将一个类的示例强转为另外一个类的,这就是 ClassLoader 隔离。
双亲委托 是 ClassLoader类一致问题的一种解决方案,也是 Android 差价化开发和热修复的基础。
Java提供了动态加载特性。在运行时的第一次引用到一个class的时候会对它进行装载(Loading) 、 链接(Linking) 和 初始化(Initialization) ,而不是在编译时进行。不同的JVM的实现不同,本文所描述的内容均只限于Hotspot JVM。
JVM的类装载器负责动态装载,Java的类装载器有如下几个特点:
加载(Loading) 首先,根据类的全限定名找到代表这个类的Class文件,然后读取到一个字节数组中。接着,这些字节会被解析检验它们是否代表一个Class对象 并包含正确的major、minor版本信息。直接父类 的类和接口也会被加载进来。这些操作一旦完成,类或者接口对象 就从二进制表示中创建出来了。
连接(Linking) 链接是检验类或接口并准备类型和父类接口的过程。链接过程包含三步:校验(Verifying)、准备(Preparing)、部分解析(Optionally resolving)。
验证
这是类装载中最复杂的过程,并且花费的时间也是最长的。任务是确保导入类型的准确性,验证阶段做的检查,运行时不需要再做。虽然减慢加了载速度,但是避免了多次检查。
准备过程通常分配一个结构用来存储类信息,这个结构中包含了类中定义的成员变量,方法 和接口信息等。
解析是可选阶段,把这个类的常量池中的所有的符号引用改变成直接引用。如果不执行,符号解析要等到字节码指令使用这个引用时才会进行。
把类中的变量初始化成合适的值。执行静态初始化程序,把静态变量初始化成指定的值。
JVM规范定义了上面的几个任务,不过它允许具体执行的时候能够有些灵活的变动。
通过类装载器装载的,被分配到JVM的运行时数据区的字节码会被执行引擎执行。
执行引擎 以指令为单位读取 Java 字节码。它就像一个 CPU 一样,一条一条地执行机器指令。每个字节码指令都由一个1字节的操作码和附加的操作数组成。执行引擎 取得一个操作码,然后根据操作数来执行任务,完成后就继续执行下一条操作码。
不过 Java 字节码是用一种人类可以读懂的语言编写的,而不是用机器可以直接执行的语言。因此,执行引擎 必须把字节码转换成可以直接被 JVM 执行的语言。
字节码 可以通过以下两种方式转换成机器语言:
解释器 一条一条地读取字节码,解释 并且 执行 字节码指令。因为它一条一条地解释和执行指令,所以它可以很快地解释字节码,但是执行起来会比较慢。这是解释执行的语言的一个缺点。字节码这种“语言”基本来说是解释执行的。
即时编译器 被引入用来弥补解释器的缺点。执行引擎 首先按照 解释执行 的方式来执行,然后在合适的时候,即时编译器 把 整段字节码 编译成 本地代码。然后,执行引擎就没有必要再去解释执行方法了,它可以直接通过本地代码去执行它。执行本地代码比一条一条进行解释执行的速度快很多。编译后的代码可以执行的很快,因为本地代码是保存在缓存里的。
Java 字节码是解释执行的,但是没有直接在 JVM 宿主执行原生代码快。为了提高性能,Oracle Hotspot 虚拟机会找到执行最频繁的字节码片段并把它们编译成原生机器码。编译出的原生机器码被存储在非堆内存的代码缓存中。
通过这种方法(JIT),Hotspot 虚拟机将权衡下面两种时间消耗:将字节码编译成本地代码需要的额外时间和解释执行字节码消耗更多的时间。
这里插入一下 Android 5.0 以后用的 ART 虚拟机使用的是 AOT 机制。
Dalvik 是依靠一个 Just-In-Time (JIT)编译器去解释字节码。开发者编译后的应用代码需要通过一个解释器在用户的设备上运行,这一机制并不高效,但让应用能更容易在不同硬件和架构上运行。ART 则完全改变了这套做法,在应用安装时就预编译字节码到机器语言,这一机制叫Ahead-Of-Time (AOT)编译。在移除解释代码这一过程后,应用程序执行将更有效率,启动更快。
标签:daemon 隔离 rap 检验 pac 编译器 限制 工具 频繁
原文地址:https://www.cnblogs.com/tyy8/p/14419975.html