当前位置: 首页 > news >正文

JVM深入 —— JVM的体系架构

前言

        能否真正理解JVM的底层实现原理是进阶Java技术的必由之路,Java通过JVM虚拟机的设计使得Java的延拓性更好,平台无关性是其同时兼顾移动端和服务器端开发的重要特性。在本篇文章中,荔枝将会仔细梳理JVM的体系架构和理论知识,希望能帮助到有需要的小伙伴~~~


文章目录

前言

一、JVM的基本概念

1.1 两种线程和生命周期

1.2 JVM的结构体系

类装载器

运行时数据区

执行引擎

1.3 平台无关性的理解 

二、JVM的内存结构

2.1 方法区

2.2 Java堆

2.3 VM Stack

2.4 本地方法栈

2.5 程序计数器

2.6 本地方法接口JNI 

三、常量池

3.1 编译时常量池

3.2 运行时常量池

3.3 字符串常量池

3.4 常量池的大小限制

总结


一、JVM的基本概念

        JVM(Java Virtual Machine)又被称为Java虚拟机,是Java程序的运行环境。我们知道在Java中程序文件.java会被编译器编译成字节码文件(.class文件),并在JVM中利用解释器解释成机器码执行。JVM是Java实现平台无关性的最关键的组件,只要对应的操作系统中有对应的JVM版本,就可以运行Java的字节码文件,实现一次编译、到处运行的场景。荔枝在看了一些资料后发现大多数的书籍和博客都是以HotSpot虚拟机来介绍的,这里荔枝也就随波逐流地来梳理一下:

1.1 两种线程和生命周期

        JVM是基于线程的,是线程对应的而不是线程共享的。JVM中的线程主要分为两种:守护线程和普通线程。其中守护线程是JVM自己使用的线程,比如垃圾回收机制(GC)就是一个守护线程;而普通线程就是一般的Java线程,只要有线程在执行那么JVM就不会停止。

那么什么时候虚拟机会结束进程呢?

JVM结束生命周期的四种情况

  • 程序正常执行完成后,无普通线程执行
  • 程序执行出现异常报错
  • 执行了System.exit()方法
  • 操作系统出错而导致JVM虚拟机进程终结 

1.2 JVM的结构体系

粗略来分,JVM的内部体系结构分为三部分:类装载器、运行时的数据区和执行引擎。  

类装载器

        类装载器又被称为类加载子系统,在JVM中提供了一套类加载机制。即JVM通过类加载器来将字节码文件加载进入内存空间,获得程序中的类和接口并赋予唯一名称。JVM的类加载器一般来说分为三种:启动类加载器、拓展类加载器和拓展类加载器,通过双亲委派模型来进行类的加载,关于双亲委派模型和类加载机制,这里我们只需要了解有这么一个概念,在荔枝的下一篇文章会详细梳理噢~

除了Java默认提供的三个加载器之外,我们还可以根据自身需求自定义ClassLoader,自定义的类加载器必须继承自 java.lang.ClassLoader 类。

运行时数据区

        运行时的数据区又称内存空间,主要包括了方法区、堆、虚拟机栈、本地方法栈和程序计数器这五部分。Java程序被编译成字节码文件后经过JVM的类加载机制就可以得到开发者定义的相关的类、接口、变量信息和代码缓存,并将这些数据注入内存空间进行储存,之后将程序指令编译成机器指令并交给执行引擎即可。

执行引擎

        执行引擎的主要职责,就是类加载后得到的程序指令集翻译成硬件所支持的指令集格式,然后执行。 在不同的虚拟机实现中,可能会有两种的执行方式:解释执行(通过解释器执行)和编译执行(通过即时编译器产生本地代码)。虚拟机可以按自身的需求,采用一种或同时采用多种组合的方式来实现执行引擎。但无论内部怎么实现,都要遵循输入的是字节码文件、处理过程是等效字节码解析过程、输出的是执行结果这个JVM规范要求。

1.3 平台无关性的理解 

        我们大致了解了JVM的运行原理和架构体系,但对于JVM的平台无关性这一性质还不是特别明确。我们知道Java在网页端和移动端的开发应用十分广泛,这正是其平台无关性的一个具体的体现。简单理解其实JVM作为一个平台对底层的硬件和上层的类对象和API做了隔离,就相当于套接件,使得我们仅需要根据不同的操作系统找到其对应的JVM版本即可完成程序迁移使用,有点开箱即用的感觉哈哈哈。


二、JVM的内存结构

JVM内存结构中不是所有的数据区都是线程隔离的,其中程序计数器、本地方法栈和VM Stack是线程隔离的;而堆、方法区和本地内存是线程共享的。

2.1 方法区

        存储类的元数据信息、静态变量、即时编译器编译后的代码缓存等。在HotSpot JVM中,方法区被称为"永久代",在Java 8及之后版本中,它被改为"元空间"(Metaspace)。相比于永久代,元空间的好处是会在运行时根据需要动态调整,只要没有超过当前进程可用的内存上限就不会出现溢出的问题,方法区可以被垃圾回收。

元数据信息

包括类的全名、父类名称、类或接口的标识、类型修饰符、所有父接口全名的列表、类型的字段信息、类型的方法信息、静态类信息、类的引用和常量池的信息。

2.2 Java堆

        存储Java对象的内存区域。所有通过new关键字创建的对象都在堆中分配内存。堆区负责存放对象实例,当Java创建一个类的实例对象或者数组时,都会在堆中为新的对象分配内存。需要注意的是:堆空间和方法区是线程共享的,堆的存取是先进先出的,堆内存的大小可以动态分配,并且堆可以由GC机制进行资源回收。

2.3 VM Stack

        在Java栈中只保存基础数据类型对象的引用,注意对象是保存在堆区中的,这里保存的是对象的引用。栈中创建的基本类型数据在超出其作用域之后就会被自动释放掉,不受GC机制的回收管理。当一个线程创建运行的时候,与之对应的栈就创建了,每个栈都是线程隔离滴。每个线程都会建立一个栈,每个栈又包含了若干个栈帧,每个栈帧对应着每个方法的每次调用,栈帧包含了三个部分:局部变量区、操作数栈区和运行环境区。

注意:像String、Integer、Byte、Short、Long、Boolean等等包装类型,它们是存放于堆中的。 

2.4 本地方法栈

        本地方法栈与虚拟机栈类似,但用于执行本地方法(Native方法),存储的也是本地方法的局部变量表,本地方法的操作数栈等信息。本地方法栈中的数据同样也不会被JVM GC管理,而是在其超出作用域之后自动释放。本地方法栈是在程序调用或JVM调用本地方法接口(Native)时候启用。 本地方法都不是使用Java语言编写的,它们可能由C或其他语言编写,本地方法也不由JVM去运行,所以本地方法的运行不受JVM管理。

注意:HotSpot VM将本地方法栈和JVM栈合并了,本地方法栈也会在深度溢出或扩展失败的时候会分别抛出StackOverflowError 和 OutOfMemoryError 异常。

2.5 程序计数器

        程序计数器(Program Counter Register):记录当前线程执行的字节码指令地址,线程切换时,程序计数器也会随之切换,每条线程都会有一个独立的程序计数器。当线程正在执行一个Java方法,程序计数器记录的是正在执行的JVM字节码指令的地址。如果正在执行的是一个Natvie(本地方法),那么这个计数器的值则为空(Underfined)。

2.6 本地方法接口JNI 

        JNI是Java Native interface的缩写,它提供了若干的API实现了Java和其他语言的通信,对于一下其它语言的库或者是函数功能的移植提供了一定的便捷度。但是需要注意的是,一旦使用了JNI,相当于主动放弃了Java的平台无关性这一特性,同时线程也不再是绝对安全的。 


三、常量池

3.1 编译时常量池

Java代码在经过编译器后,会生成一个Class文件,在编译阶段生成的这个常量池储存在Class文件里,它主要存放着 字面量、符号引用等信息,在JVM把Class文件加载完成后,编译时常量池里的数据会存放到运行时常量池中。

3.2 运行时常量池

运行时常量池是在JVM运行时生成的常量池,同时作为方法区(Method Area)的一部分,运行时常量池中存储的是基本类型的数据和对象的引用,与.class文件中的编译时常量池相对应。一般来说,JVM在对字节码文件进行类加载后,会把字节码文件内容里常量池的数据会放入运行时常量池。每一个加载好的Class对象里都会有一个运行时常量池。

3.3 字符串常量池

字符串常量池是常量池的一部分,用于存放字符串字面量。在JDK7之后,字符串常量池从方法区迁移到了堆区,它的底层实现可以理解为是一个HashTable。Java虚拟机中只会存在一份字符串常量池。字符串常量池里,存放的数据可以是引用也可以是对象实例本身。字符串常量池同时也具备运行时常量池动态性的特征,它支持运行期间将新的常量放入池中

注意:字符串常量池中的字符串是不可变的,这意味着一旦创建了一个字符串对象,它的值就不能被修改。

3.4 常量池的大小限制

  • 在JVM规范中,常量池的大小是一个ushort类型(无符号16位整数),因此常量池的最大索引是65535。
  • 当常量池中的项超过该限制时,JVM会抛出"Constant pool is too large"的错误。

总结

        在这篇文章中,荔枝主要梳理了有关JVM体系结构的知识,明确JVM的组成和基本运行原理。对于类加载机制中的双亲委派模型和GC垃圾回收机制荔枝也会在后续的文章中详细的梳理和总结。希望能帮助到有需要的小伙伴哈哈哈~~~

今朝已然成为过去,明日依然向往未来!我是小荔枝,在技术成长的路上与你相伴,码文不易,麻烦举起小爪爪点个赞吧哈哈哈~~~ 比心心♥~~~

相关文章:

JVM深入 —— JVM的体系架构

前言 能否真正理解JVM的底层实现原理是进阶Java技术的必由之路,Java通过JVM虚拟机的设计使得Java的延拓性更好,平台无关性是其同时兼顾移动端和服务器端开发的重要特性。在本篇文章中,荔枝将会仔细梳理JVM的体系架构和理论知识,希…...

dialog => :before-close的属性应用

在element-ui里面关闭弹窗的时候before-close会触发。 也就是点击X的时候回触发before-close这个属性, 代码实例: <el-dialogtitle"新增用户":visible.sync"dialogVisible"width"50%":before-close"handleClose"> handleClose…...

<van-empty description=““ /> 滚动条bug

使用 <van-empty description"" /> 时&#xff0c;图片出现了个滚动条&#xff0c;图片可以上下滑动。 代码如下&#xff1a; <block wx:if"{{courseList.length < 0}}"><van-empty description"" /> </block> <…...

使用swiper实现图片轮播功能

swiper中文官网地址:在这里 官网介绍:Swiper是纯javascript打造的滑动特效插件,面向手机、平板电脑等移动终端。 按照使用方法下载指定版本的swiper文件; 需要用到的文件有swiper-bundle.js和swiper-bundle.css文件,还需要引入map文件,不然会有警告提示; 准备工作:…...

Qt应用开发(基础篇)——时间类 QDateTime、QDate、QTime

一、前言 时间类QDateTime、QDate、QTime、QTimeZone保存了Qt的时间、日期、时区信息&#xff0c;常用的时间类部件都会用到这些数据结构&#xff0c;常用概念有年、月、日、时、分、秒、毫秒和时区&#xff0c;时间和时区就关系到时间戳和UTC的概念。 UTC时间&#xff0c;又称…...

Modbus TCP转Profinet网关modbus tcp转以太网

大家好&#xff0c;今天我们来聊一聊如何使用捷米特的Profinet转modbusTCP协议转换网关在博图上进行非透传型配置。 1, 首先&#xff0c;我们需要安装捷米特JM-TCP-PN的GSD文件&#xff0c;并根据现场设备情况配置modbusTCP地址。然后&#xff0c;在博图中添加该GSD文件&#x…...

笔记 | P4387 【深基15.习9】验证栈序列 题解

题解 问题描述 给出两个序列 pushed 和 poped&#xff0c;分别表示入栈和出栈操作的顺序。我们需要判断给定的出栈序列是否可能对应于给定的入栈序列。如果可能&#xff0c;则输出 “Yes”&#xff1b;否则&#xff0c;输出 “No”。 解题思路 读取输入&#xff1a;读取询问…...

PyTorch中nn-XXX与F-XXX的区别

nn.XXX与F.XXX PyTorch中torch.nn**&#xff08;以下简写为nn&#xff09;中的模块和torch.nn.functional&#xff08;以下简写为F&#xff09;**中的模块都提供了常用的神经网络操作&#xff0c;包括激活函数、损失函数、池化操作等。它们的主要区别如下&#xff1a; nn中的…...

zookeeper集群和kafka的相关概念就部署

目录 一、Zookeeper概述 1、Zookeeper 定义 2、Zookeeper 工作机制 3、Zookeeper 特点 4、Zookeeper 数据结构 5、Zookeeper 应用场景 &#xff08;1&#xff09;统一命名服务 &#xff08;2&#xff09;统一配置管理 &#xff08;3&#xff09;统一集群管理 &#xff08;4&a…...

第4集丨Vue 江湖 —— 计算属性

目录 一、基本使用1.1 在computed中定义1.1.1 案例1.1.2 控制台调用getter1.1.3 控制台中的data和computed 1.2 缓存效果1.3 完整写法1.3.1 案例1.3.2 效果图 1.4 简写形式 二、案例的其他实现2.1 methods实现2.2 插值语法实现 三、体会计算属性的好处3.1 复杂任务时3.2 使用计…...

Docker 容器化学习

文章目录 前言Docker架构 1、 docker安装2、启动docker服务3、设置docker随机器一起启动4、docker体验5、docker常规命令5.1、容器操作docker [run|start|stop|restart|kill|rm|pause|unpause]docker [ps|inspect|exec|logs|export|import] 5.2、镜像操作docker images|rmi|tag…...

springboot第34集:ES 搜索,nginx

#用search after解决深分页性能问题 #第一页 GET /bank/_search {"size": 10,"sort": [{"account_number": {"order": "asc"}}] }#第二页 GET /bank/_search {"size": 10,"sort": [{"account_numb…...

微信小程序中的分包使用介绍

一、分包的好处 可以优化小程序首次启动的下载时间 在多团队共同开发时可以更好的解耦协作 主包&#xff1a;放置默认启动页面/TabBar 页面&#xff0c;公共资源/JS 脚本 分包&#xff1a;根据开发者的配置进行划分 限制&#xff1a;所有分包大小不超过 20M&#xff0c;单…...

【云原生】K8S二进制搭建二:部署CNI网络组件

目录 一、K8S提供三大接口1.1容器运行时接口CRI1.2云原生网络接口CNI1.3云原生存储接口CSI 二、Flannel网络插件2.1K8S中Pod网络通信2.2Overlay Network2.3VXLAN2.4Flannel 三、Flannel udp 模式的工作原理3.1ETCD 之 Flannel 提供说明 四、vxlan 模式4.1Flannel vxlan 模式的工…...

【iOS】—— 离屏渲染

文章目录 离屏渲染UIView和CALayer关系GPU屏幕渲染有两种方式:产生离屏渲染的原因&#xff1a;既然离屏渲染这么耗性能,为什么有这套机制呢?什么情况会离屏渲染&#xff1f;既然离屏渲染这么不好&#xff0c;为什么我们还要强制开启呢&#xff1f;如何避免离屏渲染&#xff1f…...

基于人工智能的中医图像分类系统设计与实现

华佗AI 《支持中医,永远传承古老文化》 本存储库包含一个针对中药的人工智能图像分类系统。该项目的目标是通过输入图像准确识别和分类各种中草药和成分。 个人授权许可证 版权所有 2023至2050特此授予任何获得华佗AI应用程序(以下简称“软件”)副本的人免费许可,可根据以…...

spring security + oauth2 使用RedisTokenStore 以json格式存储

1.项目架构 2.自己对 TokenStore 的 redis实现 package com.enterprise.auth.config;import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis…...

css position: sticky;实现上下粘性布局,中间区域滚动

sticky主要解决的问题 1、使用absolute和fixed中间区域需要定义高度2、使用absolute和fixed底部需要写padding-bottom 避免列表被遮挡住一部分&#xff08;底部是浮窗的时候&#xff0c;需要动态的现实隐藏&#xff09; <!DOCTYPE html> <html lang"en"&…...

解密HTTP代理爬虫中的IP代理选择与管理策略

在当今数据驱动的世界中&#xff0c;HTTP代理爬虫作为一项重要的数据采集工具&#xff0c;其成功与否往往取决于IP代理的选择与管理策略。作为一家专业的HTTP代理产品供应商&#xff0c;我们深知IP代理在数据采集中的重要性。在本文中&#xff0c;我们将分享一些关于HTTP代理爬…...

pytorch入门

详细安装教程和环境配置可以看&#xff1a;Python深度学习&#xff1a;安装Anaconda、PyTorch&#xff08;GPU版&#xff09;库与PyCharm_哔哩哔哩_bilibili 跟学课程&#xff1a;B站我是土堆 pytorch中两个实用函数&#xff1a; dir()&#xff1a;打开 help():说明书…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

python如何将word的doc另存为docx

将 DOCX 文件另存为 DOCX 格式&#xff08;Python 实现&#xff09; 在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是&#xff0c;.doc 是旧的 Word 格式&#xff0c;而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...