理解JVM:从字节码到程序运行

大家好,我是程序员大猩猩。

今天我们来讲一下JVM,好多面试者在面试的时候,都会被问及JVM相关知识。那么JVM到底是什么,要理解它到底是出于什么原因?

JVM俗称Java虚拟机,它是一个抽象的计算机,是提供一个可以运行java程序的软件环境。

JVM主要的任务是加载字节码文件(Java文件编译后的.class文件)、验证字节码、执行字节码。

首先看看JVM的结构模型:

图片

  1. 类加载器(Class Loader

  • 负责将.class文件加载到JVM中

  • JVM预定义了三个类加载器:Bootstrap Class Loader、Extension Class Loader和System Class Loader。

  • 可以自定义类加载器。

如何自定义类加载器呢? 重新ClassLoader类并重写了findClass方法

public class CustomClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        try {
          // .... 
        } catch (IOException e) {
            throw new ClassNotFoundException(name);
        }
    }

     public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        CustomClassLoader loader = new CustomClassLoader();
        Class<?> clazz = loader.findClass("com.example.MyClass");
        Object instance = clazz.newInstance();
        System.out.println("Loaded class: " + instance.getClass().getCanonicalName());
    }
}

那么实现自定义类加载器可以用来干什么呢?

  • 实现热部署,即在运行时重新加载类的修改版本。

  • 加密类文件,然后在加载时解密。

  • 从非标准位置(如数据库、网络或其他专用格式)加载类文件。

2. 运行时数据区(Runtime Data Area):

  1. 方法区(Method Area)

    1.  被所有线程共享,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

    2.  当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常。

  2. 堆(Heap)

    1. Java虚拟机管理的内存中最大的一块,被所有线程共享,在虚拟机启动时创建。

    2. 唯一的目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。

    3. 垃圾回收器管理的主要区域,因此也被称作“GC堆”

  3. 栈(Stack)

    1. 每个线程创建时都会创建一个虚拟机栈,其生命周期与线程相同。

    2. 虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行时,都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

    3. 局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型,它不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向代表对象的句柄或其他与此对象相关的位置)和返回地址。

  4. 程序计数器(Program Counter Register)

    1. 存储当前线程执行的字节码的地址。每个线程都有一个程序计数器,是线程私有的。

    2. 执行Java方法时,程序计数器记录的是正在执行的虚拟机字节码指令的地址。如果是本地方法,程序计数器的值则为空(Undefined)。

  5. 本地方法栈(Native Method Stack)

    1. 为使用Java Native Interface(JNI)的本地方法服务。

    2. Native方法栈也会在栈深度溢出或栈扩展失败时抛出StackOverflowError和OutOfMemoryError异常。

3. 执行引擎(Execution Engine):

  1. 字节码加载:

    • 类加载器将.class文件加载到JVM的方法区。

    • 执行引擎通过方法区的字节码来执行程序。

  2. 解释执行:

    • 字节码最初是通过解释器逐条解释执行的。

    • 解释器快速地将字节码转换成对应的机器指令,然后执行。

  3. 即时编译(Just-In-Time Compilation,JIT):

    • 为了提高执行效率,现代JVM通常包含一个即时编译器(JIT编译器)。

    • JIT编译器将热点代码(即执行频率高的代码)编译成机器码,并将其存储起来,以便后续可以直接执行编译后的机器码,而不是再次解释执行。

    • 这种混合使用解释执行和编译执行的方法称为“即时编译”。

  4. 优化:

    • JIT编译器在编译字节码时,会进行各种优化,如方法内联、逃逸分析、循环展开等,以提高执行效率。

4.本地库接口(Native Interface):

  • 执行引擎支持JNI,允许Java代码调用其他语言编写的本地库(如C/C++库)。

  • 通过JNI,Java程序可以执行本地方法,这些方法通常是用C/C++等语言编写的,并编译成了本地机器码。

5.垃圾回收器(Garbage Collector):

  • 负责自动管理内存,回收不再使用的对象占用的内存。

  • 减轻了开发者手动管理内存的负担。

  • 执行引擎与垃圾回收器紧密合作,确保在执行过程中,不再使用的对象可以被及时回收,从而释放内存资源。

6.本地方法库(Native Method Libraries):

  • 提供了一系列本地方法,供Java程序调用。

  • 这些方法通常是用C/C++等语言编写的。

JVM的设计允许Java程序在不同的平台上运行,而无需为每个平台编译一个版本。

Java程序首先被编译成字节码,然后由JVM在各个平台上解释执行或编译执行。

这使得Java语言具有“一次编写,到处运行”(Write Once, Run Anywhere)的特性。

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员大猩猩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值