JVM(Java 虚拟机)各个组成详细总结

JVM(Java 虚拟机)

1.简介

1.1 概述

JVM 是运行操作系统之上,没有和硬件有直接交互,但有可以通过接口调用来与底层操作系统交互。

Java 能够实现一次编译,全平台运行,就是通过 JVM 来实现。通过 JVM 可以让相同的数据类型在不同的系统上运行得到统一的结果。

1.2 组成

  • 程序计数器:线程私有的,是一块很小的内存空间,作为当前线程的行号器,用于记录当前虚拟机正在执行的线程指令地址
  • 虚拟机栈:线程私有的,每个方法执行的时候都会创建一个栈帧,用于存储局部变量表、操作数、动态链接和方法返回等信息,当线程请求的栈深度超过了虚拟机允许的最大深度时,就会抛出 StackOverFlowError
  • 本地方法栈:线程私有的,保存的是 native 方法的信息,当一个 jvm 创建的线程调用 native 方法
    后,jvm 不会在虚拟机栈中为该线程创建栈帧,而是简单的动态链接并直接调用该方法
  • 堆:java 堆是所有线程共享的一块内存,几乎所有对象的实例和数组都要在堆上分配内存,因此该
    区域经常发生垃圾回收的操作
  • 方法区:存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码数据

程序计数器、虚拟机栈、本地方法栈为线程私有,堆、方法区为线程共享。

2.ClassLoder 类加载器

2.1 概述

负责将接收到的 class 文件到方法区去找相应的模版(类)进行实例化,有三种 JVM 自带的类加载器和用户自定义加载器。

加载的类信息存放于称为方法区的内存空间,常量池运行时加载到内存中,即运行时常量池(1)。

(1):在 java 1.8 以后方法区通过元空间实现,方法区存放类的信息存放到了元空间、运行时常量池存放到堆中。

运行时常量池在 Java 程序运行期间是可以动态放入新的值到常量池中,典型的方式就是 String 中的 intern() 方法。

常量池无法申请到内存空间后,会抛出 OutOfMemoryError(OOM)

2.2 类加载过程

类的整个生命周期包括:加载(Loading)、验证(Verification)、准备 (Preparation)、解析 (Resolution)、初始化 (Initialization)、使用(Using) 和 卸载(Unloading) 7个阶段。

其中准备、验证、解析3个部分统称为连接(Linking)。如图所示:

加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始,这是为了支持 Java 语言的运行时绑定(也称为动态绑定或晚期绑定)。

2.2.1 加载(Loading)
  • 通过一个类的全限定名获取定义此类的二进制字节流

    JVM 虚拟机并没有指明二进制字节流获取途径,因此许多如动态代理、JSP 等就可以从这里生成 class 文件,让虚拟机运行。

  • 将这个字节流所代表的的静态存储结果转化为方法区的运行时数据结构

  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问入口

首先加载该类的父类

加载阶段中的加载和链接可能是交替运行

2.2.2 验证 (Verification)
  • 验证

    验证类是否符合jvm规范,安全性检查

  • 准备

    为成员(static)变量分配空间,并设置默认值(默认值不是用户指定的值,而是系统对于该变量的默认值,如:int类型的默认值为0)

    • 空间分配和赋值两个阶段

    在后面的初始化阶段(即cinit阶段,调用类的构造方法)才会进行赋值,如果加上了 final 修饰符,如:static final int a = 10;会在编译阶段就会进行赋值(基本数据类型和字符串常量适用这个规则)

    注意:在 jdk6 之前是将静态变量存储在方法区,jdk7 以后是和类一起存储在堆空间中

  • 解析

    将常量池中的符号引用解析为直接引用

    将代码中的符号解析的引用类型执行具体的内存地址

2.2.3 初始化 (Initialization)

初始化阶段是执行类构造器方法()的过程。此方法不需要定义,是 javac 编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来,自动生成。

如果没有类变量和静态代码块,也不会有clinit

1.导致初始化的情况
  • main 方法所在的类,总会被首先初始化

  • 首次使用这个类的静态方法或静态变量时会初始化

  • 子类初始化,会一同进行父类的初始化

  • 子类访问父类的静态变量,只会触发父类的初始化

  • Calss.forName

    如:驱动加载

  • new 实例会导致类的初始化

2.不会导致初始化的情况
  • 访问类的 static final 静态常量(上面的加载过程中的准备阶段加载的常量,基本数据类型和字符串常量)不会触发初始化
  • 调用类对象 .class 属性不会触发初始化
  • 创建该类的数组不会发生初始化
  • 调用类的 loadClass 方法不会初始化
  • Class.forName 的设置第二个参数为 false 时不会初始化

最后就是使用和卸载阶段。

2.3 类加载器分类

2.3.1 系统自带
  • Bootstrap:启动类加载器

    加载 Java 的基本的运行环境,Java 诞生时自带的类(基础类库)通过这个加载,如:object 类

  • Extension:扩展类加载器

    除去基本的运行环境中含有的方法以外,在后续的更新中添加的一些额外扩展的类库,通过这个方式加载

  • AppClassLoader:应用程序类加载器

    Java 也叫系统类加载器,加载当前应用的 classpath 的所有类,用于加载用户自定义的类

2.3.2 自定义加载器

概念上,将所有派生于抽象类 ClassLoader 的类加载器都划分为自定义加载器。用户可以自己定义加载器的加载顺序和使用。(1)

(1):关于顺序,后面会讲解双亲委派机制,就可以了解到 JVM 内部的加载器的顺序是固定的且有要求的。

2.3.3 加载器顺序实例
public class 
  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现一个JVM虚拟机,需要深入了解JVM的内部实现原理和Java语言规范。一般来说,JVM虚拟机由以下几个模块组成: 1. 类加载器:负责从文件系统、网络或其他来源加载Java类文件,并将其转换为JVM能够理解的格式。 2. 运行时数据区:Java程序运行时需要的内存空间,包括Java堆、方法区、虚拟机栈、本地方法栈、程序计数器等。 3. 执行引擎:负责执行Java字节码,将它们转换为机器码并执行。 4. 垃圾收集器:负责回收未使用的对象,释放内存空间。 5. 本地方法接口:允许Java代码调用本地方法(C/C++代码)。 下面是一个简单的Java虚拟机实现的示例: ```java public class JVM { private ClassLoader classLoader; private RuntimeDataArea runtimeDataArea; private ExecutionEngine executionEngine; private GarbageCollector garbageCollector; private NativeMethodInterface nativeMethodInterface; public JVM() { classLoader = new ClassLoader(); runtimeDataArea = new RuntimeDataArea(); executionEngine = new ExecutionEngine(); garbageCollector = new GarbageCollector(); nativeMethodInterface = new NativeMethodInterface(); } public void run(String className) { // 加载类 Class clazz = classLoader.loadClass(className); // 初始化类 clazz.initialize(runtimeDataArea); // 执行方法 Method mainMethod = clazz.getMethod("main", String[].class); executionEngine.execute(mainMethod); } } ``` 这个简单的JVM实现只包含了类加载器、运行时数据区和执行引擎三个部分。在实现时,还需要考虑Java语言规范中的各种细节,如异常处理、线程安全等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值