LeetCode|Python|400题分类刷题记录——数组

python windows下路径找不到文件或者图片

  返回  

Java虚拟机

2021/8/21 16:35:09 浏览:

概念

直译器(解释器)这玩意?
(估计你没听过)就是每跑一行代码就生成机器码,然后执行,比如说 Python 和 Ruby 用的就是直译器。
在每个操作系统上装一个直译器就好了,跨平台的目的就达到了。

编译器负责把 Java 源代码编译成字节码(不清楚的小伙伴可以点击链接查看上一节),
Java 虚拟机(Java Virtual Machine,简称 JVM) 负责把字节码转换成机器码

Java 虚拟机虽然是虚拟的,但它的内部是可以划分为:

  • 类加载器(Class Loader)
  • 运行时数据区(Runtime Data Areas)
  • 执行引擎(Excution Engine)
    在这里插入图片描述

类加载器

类加载器是 Java 虚拟机的一个子系统,用于加载类文件。每当我们运行一个 Java 程序,它都会由类加载器首先加载。

一般来说,Java 程序员并不需要直接同类加载器进行交互。JVM 默认的行为就已经足够满足大多数情况的需求了。不过,如果遇到了需要和类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就不得不花大量的时间去调试 ClassNotFoundExceptionNoClassDefFoundError 等异常。

对于任意一个类,都需要由它的类加载器和这个类本身一同确定其在 JVM 中的唯一性。也就是说,如果两个类的加载器不同,即使两个类来源于同一个字节码文件,那这两个类就必定不相等(比如两个类的 Class 对象不 equals)。

来通过一段简单的代码了解下。

public class ClassLoadDemo {
    public static void main(String[] args) {
        /*
            每个 Java 类都维护着一个指向定义它的类加载器的引用,
            通过类名.class.getClassLoader()可以获取到此引用;
            然后通过 loader.getParent() 可以获取类加载器的上层类加载器。
         */
        ClassLoader loader=ClassLoadDemo.class.getClassLoader();
        while (loader!=null){
            System.out.println(loader);
            loader = loader.getParent();
        }
    }
}

代码运行结果:

jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
jdk.internal.loader.ClassLoaders$PlatformClassLoader@7c30a502

输出为ClassLoadDemo的类加载器,即应用类加载器,它是jdk.internal.loader.ClassLoaders$AppClassLoader类的实例

输出为平台类加载器,是jdk.internal.loader.ClassLoaders$PlatformClassLoader类的实例

按理说,扩展类加载器的上层类加载器是启动类加载器,但启动类加载器是虚拟机的内置类加载器,通常表示为 null。

运行时数据区

在这里插入图片描述

  • PC寄存器(PC Register),也叫程序计数器(Program Counter Register),是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的信号指示器。

  • JVM 栈(Java Virtual Machine Stack),与 PC 寄存器一样,JVM 栈也是线程私有的。每一个 JVM 线程都有自己的 JVM 栈,这个栈与线程同时创建,它的生命周期与线程相同。

  • 本地方法栈(Native Method Stack),JVM 可能会使用到传统的栈来支持 Native 方法(使用 Java 语言以外的其它语言[C语言]编写的方法)的执行,这个栈就是本地方法栈。

  • 堆(Heap),在 JVM 中,堆是可供各条线程共享的运行时内存区域,也是供所有类实例和数据对象分配内存的区域。

  • 方法区(Method area),在 JVM 中,被加载类型的信息都保存在方法区中。包括类型信息(Type Information)和方法列表(Method Tables)。方法区是所有线程共享的,所以访问方法区信息的方法必须是线程安全的。

  • 运行时常量池(Runtime Constant Pool),运行时常量池是每一个类或接口的常量池在运行时的表现形式,它包括了编译器可知的数值字面量,以及运行期解析后才能获得的方法或字段的引用。简而言之,当一个方法或者变量被引用时,JVM 通过运行时常量区来查找方法或者变量在内存里的实际地址。

执行引擎

  • 解释器:读取字节码流,然后执行指令。因为它是一行一行地解释和执行指令,所以它可以很快地解释字节码,但是执行起来会比较慢(毕竟要一行执行完再执行下一行)。

  • 即时(Just-In-Time,JIT)编译器:即时编译器用来弥补解释器的缺点,提高性能。执行引擎首先按照解释执行的方式来执行,然后在合适的时候,即时编译器把整段字节码编译成本地代码。然后,执行引擎就没有必要再去解释执行方法了,它可以直接通过本地代码去执行。执行本地代码比一条一条进行解释执行的速度快很多。编译后的代码可以执行的很快,因为本地代码是保存在缓存里的。

联系我们

如果您对我们的服务有兴趣,请及时和我们联系!

服务热线:18288888888
座机:18288888888
传真:
邮箱:888888@qq.com
地址:郑州市文化路红专路93号