深入解析JVM工作原理:从字节码到机器指令的全过程
一、JVM概述
Java虚拟机(JVM)是Java平台的核心组件,它实现了Java"一次编写,到处运行"的理念。JVM是一个抽象的计算机器,它有自己的指令集和运行时内存管理机制。
JVM的主要职责:
- 加载:读取.class文件并验证其正确性
- 存储:管理内存分配和垃圾回收
- 执行:解释或编译字节码为机器指令
- 安全:提供沙箱环境限制恶意代码
二、JVM架构详解
JVM由三个主要子系统组成:
1. 类加载子系统
类加载过程分为三个阶段:
- 加载:查找并加载.class文件
- 链接:
- 验证:确保.class文件符合规范
- 准备:为静态变量分配内存并初始化默认值
- 解析:将符号引用转换为直接引用
- 初始化:执行静态初始化器和静态字段初始化
类加载器层次结构:
- Bootstrap ClassLoader:加载JRE核心类库(rt.jar等)
- Extension ClassLoader:加载扩展目录(jre/lib/ext)中的类
- Application ClassLoader:加载应用程序类路径(classpath)上的类
// 查看类加载器示例
public class ClassLoaderDemo {public static void main(String[] args) {System.out.println(String.class.getClassLoader()); // null (Bootstrap加载)System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader()); // ExtClassLoaderSystem.out.println(ClassLoaderDemo.class.getClassLoader()); // AppClassLoader}
}
2. 运行时数据区
2.1 方法区(Method Area)
- 存储类信息、常量、静态变量等
- 所有线程共享
- 在HotSpot VM中称为"永久代"(PermGen),JDK8后改为"元空间"(Metaspace)
2.2 堆(Heap)
- 存储所有对象实例和数组
- 垃圾回收的主要区域
- 分为新生代(Eden, Survivor)和老年代
// 堆内存分配示例
public class HeapDemo {public static void main(String[] args) {// 对象分配在堆上Object obj1 = new Object(); // 在Eden区分配Object obj2 = new Object(); // 在Eden区分配// 触发Minor GCfor (int i = 0; i < 1000000; i++) {new Object(); // 大量创建对象触发GC}}
}
2.3 Java虚拟机栈(Java Stack)
- 线程私有,生命周期与线程相同
- 存储栈帧(Stack Frame),每个方法调用创建一个栈帧
- 栈帧包含:
- 局部变量表:存放方法参数和局部变量
- 操作数栈:方法执行的工作区
- 动态链接:指向运行时常量池的方法引用
- 方法返回地址
2.4 本地方法栈(Native Method Stack)
- 为本地(Native)方法服务
- 线程私有
2.5 程序计数器(PC Register)
- 线程私有
- 记录当前线程执行的字节码指令地址
3. 执行引擎
解释器
- 逐行解释执行字节码
- 启动快,执行慢
JIT编译器(Just-In-Time)
- 将热点代码编译为本地机器码
- 执行快,但编译耗时
- 主要编译器:
- C1编译器(Client编译器):优化启动速度
- C2编译器(Server编译器):优化峰值性能
分层编译策略(JDK7+)
- 第0层:解释执行
- 第1层:C1编译,简单优化
- 第2层:C1编译,启用少量性能监控
- 第3层:C1编译,启用全部性能监控
- 第4层:C2编译,使用性能监控信息进行深度优化
// JIT编译热点代码示例
public class JITDemo {public static void main(String[] args) {long start = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {calculate(); // 会被JIT编译}long end = System.currentTimeMillis();System.out.println("耗时: " + (end - start) + "ms");}static void calculate() {// 复杂计算逻辑int sum = 0;for (int i = 0; i < 100000; i++) {sum += i;}}
}
三、垃圾回收机制(GC)
1. 对象生命周期管理
对象分配过程:
- 优先在Eden区分配
- Eden区满时触发Minor GC
- 存活对象移到Survivor区
- 对象年龄增加到阈值(默认15)后晋升到老年代
- 老年代空间不足时触发Full GC
2. 垃圾回收算法
标记-清除(Mark-Sweep)
- 标记可达对象,清除未标记对象
- 产生内存碎片
标记-整理(Mark-Compact)
- 标记后移动存活对象整理内存
- 无碎片但效率较低
复制算法(Copying)
- 将内存分为两块,只使用一块
- GC时将存活对象复制到另一块
- 无碎片但内存利用率低
分代收集(Generational)
- 新生代使用复制算法
- 老年代使用标记-清除或标记-整理
3. 常见垃圾收集器
收集器 | 作用区域 | 算法 | 特点 |
---|---|---|---|
Serial | 新生代 | 复制 | 单线程,简单高效 |
ParNew | 新生代 | 复制 | Serial的多线程版本 |
Parallel Scavenge | 新生代 | 复制 | 吞吐量优先 |
Serial Old | 老年代 | 标记-整理 | Serial的老年代版本 |
Parallel Old | 老年代 | 标记-整理 | Parallel Scavenge的老年代版本 |
CMS | 老年代 | 标记-清除 | 低停顿,并发收集 |
G1 | 全堆 | 标记-整理+复制 | 分区收集,可预测停顿 |
ZGC | 全堆 | 染色指针 | 低延迟,大堆内存 |
Shenandoah | 全堆 | 转发指针 | 低延迟,并发压缩 |
// GC日志分析示例
// 添加JVM参数: -XX:+PrintGCDetails -Xmx20m -Xms20m
public class GCDemo {public static void main(String[] args) {for (int i = 0; i < 1000; i++) {byte[] data = new byte[1 * 1024 * 1024]; // 每次分配1MBtry {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}}
}
四、JVM性能调优
1. 内存参数设置
参数 | 描述 |
---|---|
-Xms | 初始堆大小 |
-Xmx | 最大堆大小 |
-Xmn | 新生代大小 |
-XX:NewRatio | 新生代与老年代比例 |
-XX:SurvivorRatio | Eden与Survivor区比例 |
-XX:MetaspaceSize | 元空间初始大小 |
-XX:MaxMetaspaceSize | 元空间最大大小 |
2. GC调优策略
-
新生代调优:
- 增大Eden区减少Minor GC频率
- 合理设置Survivor区避免过早晋升
-
老年代调优:
- 避免频繁Full GC
- 选择合适的收集器(CMS/G1)
-
元空间调优:
- 设置合适的Metaspace大小避免动态扩展
3. 常用诊断工具
- jps:查看Java进程
- jstat:监控JVM统计信息
jstat -gcutil <pid> 1000 10 # 每1秒打印一次GC情况,共10次
- jmap:堆内存分析
jmap -heap <pid> # 查看堆配置 jmap -histo <pid> # 查看对象直方图 jmap -dump:format=b,file=heap.hprof <pid> # 生成堆转储文件
- jstack:线程堆栈分析
jstack <pid> > thread.txt # 导出线程快照
- VisualVM:图形化监控工具
- MAT:内存分析工具
五、JVM高级特性
1. 字节码执行
// 简单方法字节码示例
public class BytecodeDemo {public static void main(String[] args) {int a = 1;int b = 2;int c = add(a, b);System.out.println(c);}static int add(int x, int y) {return x + y;}
}
使用javap -c BytecodeDemo
查看字节码:
public static void main(java.lang.String[]);Code:0: iconst_1 // 将int 1压入栈1: istore_1 // 存储到局部变量1(a)2: iconst_2 // 将int 2压入栈3: istore_2 // 存储到局部变量2(b)4: iload_1 // 加载局部变量1(a)5: iload_2 // 加载局部变量2(b)6: invokestatic #2 // 调用add方法9: istore_3 // 存储结果到局部变量3(c)10: getstatic #3 // 获取System.out13: iload_3 // 加载局部变量3(c)14: invokevirtual #4 // 调用println17: returnstatic int add(int, int);Code:0: iload_0 // 加载第一个参数(x)1: iload_1 // 加载第二个参数(y)2: iadd // 执行加法3: ireturn // 返回结果
2. 即时编译(JIT)优化技术
- 方法内联:将小方法调用替换为方法体
- 逃逸分析:确定对象作用域,可能进行栈分配或锁消除
- 循环展开:减少循环控制开销
- 公共子表达式消除:避免重复计算
- 死代码消除:移除不会执行的代码
// JIT优化示例:逃逸分析与栈上分配
public class EscapeAnalysisDemo {public static void main(String[] args) {long start = System.currentTimeMillis();for (int i = 0; i < 100000000; i++) {createObject(); // 对象可能被分配在栈上}long end = System.currentTimeMillis();System.out.println("耗时: " + (end - start) + "ms");}static void createObject() {// 对象未逃逸出方法,可能被优化为栈上分配Object obj = new Object();}
}
3. 内存模型与线程安全
Java内存模型(JMM)关键概念:
- 主内存:所有共享变量存储的位置
- 工作内存:每个线程私有的内存空间
- happens-before原则:定义操作间的可见性规则
volatile关键字:
- 保证变量的可见性
- 禁止指令重排序
- 不保证原子性
// volatile示例
public class VolatileDemo {private volatile boolean flag = false;public void writer() {flag = true; // 写操作}public void reader() {if (flag) { // 读操作System.out.println("flag is true");}}
}
六、JVM发展前沿
- GraalVM:支持多语言的高性能运行时
- Project Loom:轻量级线程(纤程)支持
- Valhalla:值类型和内联类
- Panama:改进本地方法调用
- ZGC/Shenandoah:低延迟垃圾收集器
结语
JVM是Java生态系统的核心,理解其工作原理对于编写高性能、稳定的Java应用程序至关重要。本文从类加载机制、内存结构、执行引擎到垃圾回收等多个维度深入解析了JVM的工作原理,并提供了实用的调优建议和示例代码。
掌握JVM知识不仅能帮助开发者解决内存泄漏、性能瓶颈等实际问题,还能培养对Java程序的"直觉",写出更符合JVM特性的高效代码。随着Java语言的不断发展,JVM也在持续进化,值得我们持续关注和学习。
相关文章:
深入解析JVM工作原理:从字节码到机器指令的全过程
一、JVM概述 Java虚拟机(JVM)是Java平台的核心组件,它实现了Java"一次编写,到处运行"的理念。JVM是一个抽象的计算机器,它有自己的指令集和运行时内存管理机制。 JVM的主要职责: 加载:读取.class文件并验…...
MCP通信方式之Streamable HTTP
目录 一、前言二、三种传输方式对比1、Stdio和 HTTP SSE工作原理2、Streamable HTTP3、Streamable HTTP解决什么问题三、Streamable HTTP MCP设计原理四、Streamable HTTP MCP demo演示1、MCP server示例2、MCP Client示例一、前言 2025年5月9日,MCP(Model Context Protocol)…...
第七十三篇 从电影院售票到停车场计数:生活场景解析Java原子类精髓
目录 一、原子类基础:电影院售票系统1.1 传统售票的并发问题1.2 原子类解决方案 二、原子类家族:超市收银系统2.1 基础类型原子类2.2 数组类型原子类 三、CAS机制深度解析:停车场管理系统3.1 CAS工作原理3.2 车位计数器实现 四、高性能实践&a…...

【原创】基于视觉模型+FFmpeg+MoviePy实现短视频自动化二次编辑+多赛道
AI视频处理系统功能总览 🎯 系统概述 这是一个智能短视频自动化处理系统,专门用于视频搬运和二次创作。系统支持多赛道配置,可以根据不同的内容类型(如"外国人少系列"等)应用不同的处理策略。 Ἵ…...

C++----剖析list
前面学习了vector和string,接下来剖析stl中的list,在数据库中学习过,list逻辑上是连续的,但是存储中是分散的,这是与vector这种数组类型不同的地方。所以list中的元素设置为一个结构体,将list设计成双向的&…...

纳米AI搜索与百度AI搜、豆包的核心差异解析
一、技术定位与设计目标 1、纳米AI搜索:轻量化边缘计算导向 专注于实时数据处理与资源受限环境下的高效响应,通过算法优化和模型压缩技术,实现在物联网设备、智能终端等低功耗场景的本地化部署。其核心优势在于减少云端依赖,保障…...

不到 2 个月,OpenAI 火速用 Rust 重写 AI 编程工具。尤雨溪也觉得 Rust 香!
一、OpenAI 用 Rust 重写 Codex CLI OpenAI 已用 Rust 语言重写了其 AI 命令行编程工具 Codex CLI,理由是此举能提升性能和安全性,同时避免对 Node.js 的依赖。他们认为 Node.js “可能让部分用户感到沮丧或成为使用障碍”。 Codex 是一款实验性编程代理…...
人工智能:网络安全的“智能守护者”
在数字化时代,网络安全已经成为企业和个人面临的重大挑战。随着网络攻击的复杂性和频率不断增加,传统的安全防护手段已经难以应对。人工智能(AI)技术的出现为网络安全带来了新的希望和解决方案。本文将探讨人工智能在网络安全中的…...

Python60日基础学习打卡Day46
一、 什么是注意力 注意力机制的由来本质是从onehot-elmo-selfattention-encoder-bert这就是一条不断提取特征的路。各有各的特点,也可以说由弱到强。 其中注意力机制是一种让模型学会「选择性关注重要信息」的特征提取器,就像人类视觉会自动忽略背景&…...
综述论文解读:Editing Large Language Models: Problems, Methods, and Opportunities
论文为大语言模型知识编辑综述,发表于自然语言处理顶会ACL(原文链接)。由于目前存在广泛的模型编辑技术,但一个统一全面的分析评估方法,所以本文: 1、对LLM的编辑方法进行了详尽、公平的实证分析,探讨了它们各自的优势…...

WEB3全栈开发——面试专业技能点P1Node.js / Web3.js / Ethers.js
一、Node.js 事件循环 Node.js 的事件循环(Event Loop)是其异步编程的核心机制,它使得 Node.js 可以在单线程中实现非阻塞 I/O 操作。 🔁 简要原理 Node.js 是基于 libuv 实现的,它使用事件循环来处理非阻塞操作。事件…...

Vscode下Go语言环境配置
前言 本文介绍了vscode下Go语言开发环境的快速配置,为新手小白快速上手Go语言提供帮助。 1.下载官方Vscode 这步比较基础,已经安装好的同学可以直接快进到第二步 官方安装包地址:https://code.visualstudio.com/ 双击一直点击下一步即可,记…...
Java八股文——MySQL篇
文章目录 Java八股文——MySQL篇慢查询如何定位慢查询?如何分析慢SQLExplain标准答案 索引索引类型索引底层数据结构什么是聚簇索引什么是非聚簇索引?(二级索引)(回表)聚集索引选取规则回表查询 什么是覆盖…...
Oracle数据库学习笔记 - 创建、备份和恢复
Oracle数据库学习笔记 创建,备份和恢复 Oracle 版本基于11g 尽量不使用图形界面方式,操作适用于linux和windows 创建数据库 创建实例 # 步骤1:设置环境变量 export ORACLE_SIDmyorcl export ORACLE_HOME/u01/app/oracle/product/19.0.0/dbh…...

Go语言--语法基础5--基本数据类型--输入输出(1)
I : input 输入操作 格式化输入 scanf O : output 输出操作 格式化输出 printf 标准输入 》键盘设备 》 Stdin 标准输出 》显示器终端 》 Stdout 异常输出 》显示器终端 》 Stderr 1 、输入语句 Go 语言的标准输出流在打印到屏幕时有些参数跟别的语言…...

永磁同步电机无速度算法--自适应龙贝格观测器
一、原理介绍 传统龙伯格观测器,在设计观测器反馈增益矩阵K时,为简化分析与设计,根据静止两相坐标系下的对称关系,只引入了K、K,两个常系数,且在实际应用时,大多是通过试凑找到一组合适的反馈增益系数缺乏…...

LangChain工具集成实战:构建智能问答系统完整指南
导读:在人工智能快速发展的今天,如何构建一个既能理解自然语言又能调用外部工具的智能问答系统,成为许多开发者面临的核心挑战。本文将为您提供一套完整的解决方案,从LangChain内置工具包的基础架构到复杂系统的工程实践。 文章深…...

【razor】x264 在 的intra-refresh和IDR插帧
你提到的是这样一个情况: 使用 DirectShow 采集,帧率稳定(如回调了20帧)使用 x264 的 total intra refresh 模式(intra-refresh=1) 进行编码但编码过程中「隔几十秒才有一帧intra(关键帧)」这不正常,具体分析如下: 🎯 一、问题核心 x264 的 intra refresh 模式(特…...
分库分表的取舍
文章目录 大数据量下采用**水平分表**的缺点**1. 跨表查询复杂性与性能下降****2. 数据分布不均衡****3. 分布式事务与一致性问题****4. 扩展性受限****5. 查询条件限制与索引管理复杂****6. 数据迁移与维护成本高****7. 业务逻辑复杂度增加****总结** shardingJdbc分片策略**1…...

随机算法一文深度全解
随机算法一文深度全解 一、随机算法基础1.1 定义与核心特性1.2 算法优势与局限 二、随机算法经典案例2.1 随机化快速排序原理推导问题分析与策略代码实现(Python、Java、C) 2.2 蒙特卡罗方法计算 π 值原理推导问题分析与策略代码实现(Python…...

在 Conda 环境下配置 Jupyter Notebook 环境和工作目录
作为数据科学家或Python开发者,Jupyter Notebook 是我们日常工作的得力工具。本文将详细介绍如何在 Conda 环境中配置 Jupyter Notebook,包括环境设置和工作目录管理,帮助你打造高效的工作流程。 为什么要在 Conda 环境中使用 Jupyter Noteb…...

MS39531N 是一款正弦驱动的三相无感直流电机驱动器,具有最小振动和高效率的特点
MS39531N 是一款正弦驱动的三相无感直流电机驱动器,具有最小振动和高效率的特点 简述 MS39531 是一款正弦驱动的 三相无感直流电机驱动器 ,具有最小振动和高效率的特点。该驱动器内部集成了基本的闭环速度控制功能,能够根据特定的应用定制电…...

web3-基于贝尔曼福特算法(Bellman-Ford )与 SMT 的 Web3 DeFi 套利策略研究
web3-基于贝尔曼福特算法(Bellman-Ford )与 SMT 的 Web3 DeFi 套利策略研究 如何找到Defi中的交易机会 把defi看做是一个完全开放的金融产品图表,可以看到所有的一切东西;我们要沿着这些金融图表找到一些最优的路径,就…...

分析 java 的 Map<String,Map<String, List<Map<String,Integer>>>>
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;public class Test02 {public static void main(String[] args) {//分析方法:由外层向内层逐渐拆解要定义的变量。再由内向外进行变量赋值//外层第一层&#x…...

ChatterBox - 轻巧快速的语音克隆与文本转语音模型,支持情感控制 支持50系显卡 一键整合包下载
ChatterBox 是一个近期备受关注的开源语音克隆与文本转语音(TTS)模型,由 Resemble AI 推出,具备体积轻巧及超快的推理速度等特色。它也是首个支持情感夸张控制的开放源代码 TTS 模型,这一强大功能能让您的声音脱颖而出…...

前端开发面试题总结-HTML篇
文章目录 HTML面试高频问答一、HTML 的 src 和 href 属性有什么区别?二、什么是 HTML 语义化?三、HTML的 script 标签中 defer 和 async 有什么区别?四、HTML5 相比于 HTML有哪些更新?五、HTML行内元素有哪些? 块级元素有哪些? 空(void)元素有哪些?六、iframe有哪些优点…...

嵌入式学习--江协stm32day4
只能说拖延没有什么好结果,欠下的债总是要还的。 ADC 模拟信号转化为数字信号,例如温度传感器将外部温度的变化(模拟信号),转换为内部电压的变化(数字信号) IN是八路输入,下方是选择…...

【Matlab】连接SQL Server 全过程
文章目录 一、下载与安装1.1 SQL Server1.2 SSMS1.3 OLE DB 驱动程序 二、数据库配置2.1 SSMS2.2 SQL Server里面设置2.3 设置防火墙2.4 设置ODBC数据源 三、matlab 链接测试 一、下载与安装 微软的,所以直接去微软官方下载即可。 1.1 SQL Server 下载最免费的Ex…...
MS8551/MS8552/MS8554 单电源、轨到轨输入输出、高精度运放,可替代AD8551/AD8552/AD8554
MS8551/MS8552/MS8554 单电源、轨到轨输入输出、高精度运放,可替代AD8551/AD8552/AD8554 简述 MS8551/8552/8554 是轨到轨输入输出的高精度运算放大器,它有极低的输入失调电压和偏置电流,单电源电压范围为 1.8V 到 5V 。 MS8551/8552/85…...
什么是 Ansible 主机和组变量
Ansible 是一款强大的自动化工具,可简化配置管理、应用程序部署和预配等 IT 任务。其最有价值的功能之一是能够定义变量,从而为不同的主机和组定制剧本。本文将解释 Ansible 中组变量和主机变量的概念,并通过实际示例说明它们的用法。 Ansib…...