JVM执行流程

2023-09-18 18:07:08

一、Java为什么是一种跨平台的语言?


通常,我们编写的java源代码会被JDK的编译器编译成字节码文件,再由JVM将字节码文件翻译成计算机读的懂得机器码进行执行;因为不同平台使用的JVM不一样,所以不同的JVM会把相同的字节码文件翻译成不同操作系统认识的机器码,这样就实现了跨平台;

二、Java代码的执行流程


解释执行为主,编译执行为辅:
JIT编译器:当虚拟机发现某个方法或代码块运行特别频繁时,就会把这些代码认定为(Hot Spot Code 热点代码,为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并保存到虚拟机内存中;

三、类加载的过程


3.1、加载


通过类的完全限定名称获取定义该类的二进制字节流。将该字节流表示的静态存储结构转换为Metaspace元空间区的运行时存储结构。在内存中生成一个代表该类的 Class 对象,作为元空间区中该类各种数据的访问入口。

类加载器(就是加载类的)分为:
3.1.1、启动类加载器(Bootstrap ClassLoader):


加载java核心类库,不继承ClassLoader,只加载包名为java,javax,sun开头的类;

3.1.2、扩展类加载器(Extension ClassLoader):


加载javax开头的扩展类库,继承自ClassLoader,父类加载器为启动类加载器,从java.ext.dirs指定的路径下加载类库;或者从JDK安装目录的jre/lib/ext目录下加载类库,如果用户自定义的jar包放在jre/lib/ext下,也会自动由扩展类加载器加载;

3.1.3、应用程序类加载器(Application ClassLoader):


加载用户自定义或者第三方jar包,继承自ClassLoader,父类加载器为扩展类加载器,负责加载环境变量classpath或系统属性java.class.path指定的类库,java中自己写的类都是由应用程序类加载器加载的,可以通过ClassLoader.getSystemClassLoader()方法获取该类加载器;

双亲委派模型:
一个类加载器首先将类加载请求转发到父类加载器,只有当父类加载器无法完成时才尝试自己加载。如果有人想替换系统级别的类:String.java。篡改它的实现,在这种机制下这些系统的类已经被Bootstrap classLoader加载过了,所以其他类加载器并没有机会再去加载,从一定程度上防止了危险代码的植入。 

 3.2、验证


这一阶段的主要目的是为了确保 Class 文件的字节流中包含的信息是否符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

3.3、准备


类变量是被 static 修饰的变量,准备阶段为类变量分配内存并设置初始值,使用的是元空间区的内存。初始值一般为 0 值。(如果类变量是常量,那么它将初始化为表达式所定义的值而不是 0。)

3.4、解析


将常量池的符号引用替换为直接引用的过程。其中解析过程在某些情况下可以在初始化阶段之后再开始,这是为了支持 Java 的动态绑定。

3.5、初始化


初始化阶段才真正开始执行类中定义的 Java 程序代码。初始化阶段是虚拟机执行类构造器 <clinit>()方法的过程。在准备阶段,类变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划去初始化类变量和其它资源。

四、 主动引用


4.1、字节码指令


当 jvm 执行 new指令时会加载类。即:当程序创建一个类的实例对象。

当 jvm 执行 getstatic指令时会加载类。即:程序访问类的静态变量(不是静态常量,常量会被加载到运行时常量池)。

当 jvm 执行 putstatic指令时会加载类。即:程序给类的静态变量赋值。

当 jvm 执行 invokestatic指令时会加载类。即:程序调用类的静态方法。

4.2、反射


使用 java.lang.reflect包的方法对类进行反射调用时如 Class.forname("..."), 或newInstance() 等等。如果类没初始化,需要触发类的加载。

4.3、父类加载


加载一个类,如果其父类还未加载,则先触发该父类的加载。

4.4、主类


当虚拟机启动时,用户需要定义一个要执行的主类 (包含 main() 方法的类),虚拟机会先加载这个类。

4.5、接口的实现类


当一个接口中定义了 JDK8 新加入的默认方法(被 default 关键字修饰的接口方法)时,如果有这个接口的实现类发生了加载,则该接口要在实现类之前被加载。

五、被动引用


1,通过子类引用父类的静态字段,不会导致子类加载。

2,通过数组定义来引用类,不会触发此类的加载。该过程会对数组类进行加载,数组类是一个由虚拟机自动生成的、直接继承自 Object 的子类,其中包含了数组的属性和方法。

3,常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的加载。

六、对象的创建过程


6.1、类加载检查


虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。

6.2、分配内存


在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需的内存大小在类加载完成后便可确定,为对象分配空间的任务等同于把一块确定大小的内存从 Java 堆中划分出来。内存分配的查找方式有 “指针碰撞” 和 “空闲列表” 两种。(选择以上两种方式中的哪一种,取决于 Java 堆内存是否规整。而 Java 堆内存是否规整,取决于 GC 收集器的算法是"标记-清除",还是"标记-整理"。)

6.3、初始化零值


内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段在 Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。

6.4、设置对象头


初始化零值完成之后,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息。 这些信息存放在对象头中。 另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。

6.5、执行 init 构造方法


在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从Java 程序的视角来看,对象创建才刚开始,<init> 构造方法还没有执行,目前所有的字段都还为零。所以一般来说,执行 new 指令之后会接着执行 <init> 构造方法,把对象按照程序逻辑的意愿进行初始化,这样一个真正可用的对象才算完整创建出来。

更多推荐

云原生Kubernetes:K8S集群list-watch机制与 pod调度约束

目录一、理论1.K8S的list-watch机制2.亲和性二、实验1.指定调度节点2.节点亲和性3.亲和性和反亲和三、问题1.新生成pod一直为pending2.如何一次性删除pod和deployment3.pod亲和性资源报错4.pod反亲和性资源报错四、总结一、理论1.K8S的list-watch机制(1)概念Ku

前端防抖和节流

前端防抖和节流概述防抖:防止抖动,个人字面理解此处防的不是页面的抖动,而是用户手抖。为了防止用户快速且频繁的触发事件而导致多次执行事件函数,这样的场景有很多,比如监听滚动、鼠标移动事件onmousemove、频繁点击表单的提交按钮等等。节流:节约流量,为了节约流量,页面在一个时间周期内,只触发一次动作。所以节流的目的时

CSS笔记

选择器通配选择器*{}元素选择器元素{}类选择器.类名{}id选择器#id名{}复合选择器交集选择器/*p元素且类名为beauty的元素*/p.beauty{}.rich.beauty{}并集选择器又称分组选择器.rich,.beauty,.navtop,#myIMage{}后代选择器<!--选中后代中所有li--><

python小程序 图书馆图书借阅借还管理系统 mbc21

为设计一个安全便捷,并且使借阅者更好获取本图书借还信息,本文主要有安全、简洁为理念,实现借阅者快捷寻找图书借还信息,从而解决图书借还信息复杂难辨的问题。该系统以django架构技术为基础,采用python语言和MySQL数据库进行开发设计,通过对图书借还管理流程的分析,分析了其功能性和非功能性需求,设计了基于微信小程序

设计模式:桥接模式

目录组成部分代码实现优缺点总结桥接模式是一种软件设计模式,用于将抽象部分与其实现部分分离,使它们可以独立地变化。该模式通过创建一个桥接接口,将抽象类和实现类连接起来,从而使它们可以独立地进行修改和扩展。桥接模式可以提高系统的灵活性和可扩展性,同时也有助于简化系统的设计。组成部分桥接模式的各个组成部分包括:抽象部分(Ab

有了Spring为什么还需要SpringBoot呢

目录一、Spring缺点分析二、什么是SpringBoot三、SpringBoot的核心功能3.1起步依赖3.2自动装配一、Spring缺点分析1.配置文件和依赖太多了!!!spring是一个非常优秀的轻量级框架,以IOC(控制反转)和AOP(面向切面)为思想内核,极大简化了JAVA企业级项目的开发。虽然Spring的

docker - 分享

1.docker介绍:Docker是一种虚拟化技术,它允许你在一台机器上运行多个应用程序,每个应用程序都运行在一个独立的虚拟器中,互相之间不会干扰。这些容器使用了操作系统级别的虚拟化技术,课可以在同一物理机器上运行多个应用程序,同时每个容器又拥有自己独立的文件系统和资源管理。Docker可以让你快速地创建、部署、和复制

开心档之JavaScript 异步编程

JavaScript异步编程目录JavaScript异步编程异步的概念什么时候用异步编程回调函数实例实例实例异步AJAX实例实例异步的概念异步(Asynchronous,async)是与同步(Synchronous,sync)相对的概念。在我们学习的传统单线程编程中,程序的运行是同步的(同步不意味着所有步骤同时运行,而

云原生微服务治理 第五章 Spring Cloud Netflix 之 Ribbon

系列文章目录第一章Java线程池技术应用第二章CountDownLatch和Semaphone的应用第三章SpringCloud简介第四章SpringCloudNetflix之Eureka第四章SpringCloudNetflix之Ribbon文章目录系列文章目录@[TOC](文章目录)前言1、负载均衡1.1、服务端负

Python in Visual Studio Code 2023年9月更新

作者:CourtneyWebster-ProgramManager,PythonExtensioninVisualStudioCode排版:AlanWang我们很高兴地宣布VisualStudioCode的Python和Jupyter扩展将于2023年9月发布!此版本包括以下内容:•将Python的“Recreate”

uniapp----微信小程序 日历组件(周日历&& 月日历)【Vue3+ts+uView】

uniapp----微信小程序日历组件(周日历&&月日历)【Vue3+ts+uView】用Vue3+ts+uView来编写日历组件;存在周日历和月日历两种显示方式;高亮显示当天日期,红点渲染有数据的日期,点击显示数据1.calendar-week-mouth组件代码<template><viewclass="calen

热文推荐