JVM 学习笔记 II

本文详细阐述了JVM作为Java程序与硬件系统的接口,其架构包括类加载器、运行时数据区和执行引擎。重点介绍了类加载器的工作流程、双亲委派模型及其安全性,以及运行时数据区的组成部分如程序计数寄存器、JVM栈、本地方法栈、方法区、运行时常量池和堆。此外,解释了字节码的解释执行与即时编译过程,强调了执行引擎中的垃圾收集器功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JVM是编译后的Java程序(.class文件)和硬件系统之间的接口。

JVM架构如下:

由上图可见,JVM的输入时.class文件。大致分为三部分:

  1. 类加载器 Classloader Subsystem
  2. 运行时数据区 Runtime Data Area
  3. 执行引擎 Execution Engine

除此之外,还有本地方法接口、本地方法库,也就是调用的不同的平台的库函数,体现了跨平台性。

Classloader把.class文件加载到Runtime Data Area中,然后由Execution Engine来执行Java字节码


Classloader


类加载器是动态加载的,即在运行时遇到这个类时才进行加载,而不是在编译时进行,这样更加合理。

双亲委派模型(Parent Delegation Model):

类加载器具有层次结构 ,可以看做父子关系。

  • Bootstrap classloader:当运行JVM时就被创建,负责加载核心类库。是所有类加载器的父类,由c/c++实现。
  • Extension classloader:加载除了基本Java API之外的一些扩展类
  • System classloader:加载应用程序类,也就是用户自定义的类
  • User-defined classloader:用户也可以自己开发类加载器

可以看到,类加载器自上到下具有父子关系,最上方是根。

双亲委派模型:

类加载过程遵循该模型规定。除了根累加器外,其余类加载器都应该有自己的父类加载器。每个类加载器都有自己的命名空间。工作过程如下:

  1. 当前类加载器首先在自己加载的类缓存中查询,如果已经加载则直接返回。
  2. 如果没有,则去上层父类加载器中加载,直到根加载器。
  3. 如果所有上层类加载器都没有加载,则由当前类加载器加载,并放入自己的缓存。

需要注意的是,查找只能是由下至上的,父类加载器不能查询下层子类加载器。
可以看见,这种机制提供了安全性和层级性。越基础的类的加载越在靠近根的地方被加载,用户自定义的类在加载时必须不与上层的基础类矛盾才能加载。层次结构也方便了类的划分组织。

从中可以体现Java的一个原则——类是最小逻辑组织单元。一切的底层工作都以类为单位展开。


Runtime Data Area


运行时数据区是操作系统分配的内存区域。划分如下:
这里写图片描述

可以看到,有些部分为线程私有,有的则是类中所有线程共享的。

  • 程序计数寄存器(PC register):线程私有,启动时创建。保存当前执行的JVM指令的地址。可以表明当前程序的下一条指令到哪去取。
  • JVM栈(JVM Stack):线程私有,启动时创建。对栈帧(Stack Frame)push/pop。JVM描述的是Java方法执行的过程:每个方法被执行的时候都会创建一个栈帧,来存储方法中的信息包括局部变量数组(存储包括方法参数的全部局部变量)、操作数栈(每个方法都在操作数栈和局部变量数组之间交换数据,操作数栈之内的操作数不仅可以来自局部变量数组,也可以来自常量池中的引用)、对运行时常量池(见下文)的引用等。每一个方法的调用直到执行完成就对应着一个栈帧在JVM栈中入栈到出栈的过程。
  • 本地方法栈(Native method stack):线程私有,启动时创建。为被调用的非Java实现的本地方法提供栈,即通过JNI(Java Native Interface Java本地接口)调用的c/c++代码,这部分接口在源代码中以native关键字描述。根据语言,创建b的栈。不同
  • 方法区(Method Area):线程共享。保存被JVM加载的类和接口的运行时常量池,成员变量,方法的信息,静态变量等。即类级别的信息。
  • 运行时常量池(Runtime constant pool):线程共享。包含在方法区中。其中包含所有方法、变量的引用,即在内存中的实际地址(JVM栈中的某个栈帧的具体位置)。
  • 堆(Heap):保存实例或者对象,是垃圾回收(GC)的主要目标。所有通过new关键字创建的变量都存储在堆中。

需要注意的是,Java内存模型中是没有寄存器的概念的,它以栈为主体进行内存管理。以索引来代替实际的内存地址。索引根据具体指令可能指向操作数栈或者常量池。


Execution Engine


通过类加载器加载,被分配到JVM的运行时数据区的字节码被执行引擎执行。它以指令为单位取Java字节码,类似于CPU。字节码由一个字节的的操作码和附加的操作数组成。

Java字节码还不是JVM能够直接执行的语言。字节码通过以下方式转化:

  • 解释器:读一条指令,解释,执行。重复这个过程。不保存解释后的结果。
  • 即时(Just-In-Time)编译器:把整段字节码先翻译成机器码,供执行引擎直接执行。执行起来很快因为翻译结果保存在了缓存中,但是编译所花的时间比逐条解释要慢。

JIT编译器采用检查策略:如果一个方法执行频率超过阈值,则被编译成本地机器码。对于那些执行次数很少的代码,由解释器直接解释执行。
不同的JIT采用不同策略

执行引擎中的垃圾收集器(Garbage Collector)单独作为一个模块介绍。

参考文献、博客:

深入理解JVM内幕
JVM 的 工作原理,层次结构 以及 GC工作原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值