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

JVM 深度解析

一、JVM 概述
1.1 什么是 JVM?

JVM(Java Virtual Machine,Java 虚拟机)是 Java 程序运行的核心引擎。它像一个“翻译官”,将 Java 字节码转换为机器能理解的指令,并管理程序运行时的内存、线程等资源。

核心功能

  • 跨平台运行:一次编译,到处运行(Write Once, Run Anywhere)
  • 内存管理:自动分配和回收内存(垃圾回收)
  • 安全控制:字节码验证、权限管理

类比说明

  • Java 程序 → 一本用中文写的菜谱
  • JVM → 一位精通各国语言的厨师
  • 不同操作系统 → 不同国家的厨房
  • 字节码 → 国际通用的菜谱符号
二、JVM 核心架构

JVM 由三大核心模块组成:

模块功能关键技术
类加载系统加载.class文件到内存双亲委派机制
运行时数据区管理程序运行时的内存分配堆、栈、方法区
执行引擎解释/编译字节码为机器指令解释器、JIT编译器、垃圾回收

三、类加载机制
3.1 类加载流程

类加载分为三个阶段:

  1. 加载(Loading)
    • 查找.class文件
    • 将字节码转换为方法区的数据结构
  2. 链接(Linking)
    • 验证:检查字节码是否符合规范
    • 准备:为静态变量分配内存(默认初始值)
    • 解析:将符号引用转为直接引用
  3. 初始化(Initialization)
    • 执行静态代码块(<clinit>方法)
    • 为静态变量赋真实值

示例

public class Demo {static int value = 10; // 准备阶段 value=0,初始化阶段 value=10static {System.out.println("静态代码块执行");}
}
3.2 双亲委派模型

加载器层级

  1. Bootstrap ClassLoader:加载jre/lib核心库(如java.lang.*)
  2. Extension ClassLoader:加载jre/lib/ext扩展库
  3. Application ClassLoader:加载用户类路径(classpath)
  4. 自定义ClassLoader:用户自定义加载逻辑

工作流程

  1. 子加载器收到加载请求后,先委派父加载器处理
  2. 父加载器无法完成时,子加载器才尝试加载

优势

  • 避免核心类被篡改(如自定义java.lang.String)
  • 保证类全局唯一性
  • public class ClassLoaderDemo {public static void main(String[] args) {// 查看不同类的加载器System.out.println(String.class.getClassLoader()); // null(Bootstrap加载器)System.out.println(ClassLoaderDemo.class.getClassLoader()); // AppClassLoader}
    }
    
    四、运行时数据区
    4.1 内存结构总览
  • +-------------------+
    |   方法区(Method Area)   | ← 存储类信息、常量、静态变量
    +-------------------+
    |   堆(Heap)              | ← 所有对象实例和数组
    +-------------------+
    |   虚拟机栈(VM Stack)     | ← 线程私有的方法调用栈帧
    |   本地方法栈(Native Stack)| ← 调用本地(Native)方法
    |   程序计数器(PC Register) | ← 当前线程执行的字节码行号
    +-------------------+
    
    4.2 堆(Heap)
  • 分代设计
    • 新生代(Young Generation):新创建的对象
      • Eden区(80%)
      • Survivor区(From + To,各10%)
    • 老年代(Old Generation):长期存活的对象
    • 元空间(Metaspace,JDK8+):类元数据(替代永久代)
  • 对象分配流程

  • 新对象优先分配到Eden区
  • Eden满时触发Minor GC
  • 存活对象复制到Survivor区(年龄+1)
  • 年龄达到阈值(默认15)后进入老年代

示例代码

public class HeapDemo {public static void main(String[] args) {List<byte[]> list = new ArrayList<>();while (true) {list.add(new byte[1024 * 1024]); // 持续创建1MB数组,触发OOM}}
}
// 输出:java.lang.OutOfMemoryError: Java heap space
4.3 虚拟机栈(VM Stack)
  • 栈帧结构
    • 局部变量表(Local Variables)
    • 操作数栈(Operand Stack)
    • 动态链接(Dynamic Linking)
    • 方法返回地址(Return Address)
  • 栈溢出示例
  • public class StackOverflowDemo {static void recursiveCall() {recursiveCall(); // 无限递归}public static void main(String[] args) {recursiveCall();}
    }
    // 输出:java.lang.StackOverflowError
    
    4.4 方法区(Method Area)
  • 存储内容
    • 类结构信息(字段、方法、构造函数)
    • 运行时常量池
    • JIT编译后的代码缓存
  • 元空间溢出示例

  • public class MetaspaceOOM {static class OOMObject {}public static void main(String[] args) {// 使用CGLIB动态生成类Enhancer enhancer = new Enhancer();enhancer.setSuperclass(OOMObject.class);enhancer.setCallback((MethodInterceptor) (obj, method, args1, proxy) -> proxy.invokeSuper(obj, args1));while (true) {enhancer.create(); // 持续生成代理类}}
    }
    // 输出:java.lang.OutOfMemoryError: Metaspace
    
    五、垃圾回收(GC)
    5.1 判断对象可回收
  • 引用计数法:循环引用问题(已弃用)
  • 可达性分析:从GC Roots出发,不可达的对象可回收
    • GC Roots包括:
      • 虚拟机栈中引用的对象
      • 方法区中静态属性引用的对象
      • 本地方法栈中JNI引用的对象
  • 示例
  • public class GCRootsDemo {Object instance;public static void main(String[] args) {GCRootsDemo a = new GCRootsDemo();GCRootsDemo b = new GCRootsDemo();a.instance = b;b.instance = a;a = null;b = null; // 此时两个对象仍互相引用,但不可达,会被回收System.gc();}
    }
    
    5.2 垃圾回收算法
    算法原理适用场景
    标记-清除标记可回收对象后清除老年代(CMS)
    复制将存活对象复制到新空间新生代(Serial、ParNew)
    标记-整理标记后整理内存空间老年代(Serial Old)
    分代收集根据对象年龄采用不同算法现代JVM默认方案

复制算法示意图

新生代内存布局:
+-----------+------------+-----------+
|   Eden    | From(S0)   | To(S1)    |
+-----------+------------+-----------+
Minor GC后存活对象复制到To区,清空Eden和From
5.3 垃圾收集器
收集器特点适用场景
Serial单线程,Stop-The-World客户端模式
ParNewSerial的多线程版本新生代(配合CMS)
CMS并发标记清除,低停顿老年代
G1分区收集,可预测停顿时间JDK9+默认
ZGC低延迟(<10ms),大堆内存超大内存应用

G1收集器示例配置

java -XX:+UseG1GC -Xmx4g -XX:MaxGCPauseMillis=200 MyApp
六、执行引擎
6.1 解释执行
  • 逐行解释字节码:效率低,但启动快
  • 示例javap -c MyClass.class 查看字节码
6.2 JIT编译(Just-In-Time)
  • 热点代码检测:统计方法调用次数
  • 编译优化技术
    • 方法内联(Method Inlining)
    • 逃逸分析(Escape Analysis)
    • 循环展开(Loop Unrolling)

逃逸分析示例

public class EscapeAnalysisDemo {public static void main(String[] args) {for (int i = 0; i < 1000000; i++) {createObject();}}static void createObject() {Object obj = new Object(); // 对象未逃逸,可能被栈上分配}
}
6.3 分层编译(Tiered Compilation)
  • 编译级别
    • 0:解释执行
    • 1:简单快速编译(C1)
    • 2:完全优化编译(C2)
  • 参数控制-XX:TieredStopAtLevel=3

七、性能监控与调优
7.1 常用工具
工具功能示例命令
jps查看Java进程IDjps -l
jstat监控GC情况jstat -gcutil <pid> 1000
jmap生成堆转储快照jmap -dump:format=b,file=heap.bin <pid>
VisualVM图形化性能分析监控CPU、内存、线程

jstat输出示例

S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
0.00 100.00  25.43  68.50  95.12  91.03     10    0.123     2    0.456    0.579
7.2 常见JVM参数
参数作用示例值
-Xms / -Xmx初始/最大堆内存-Xms512m -Xmx4g
-XX:NewRatio新生代与老年代比例-XX:NewRatio=3(新生代占1/4)
-XX:SurvivorRatioEden与Surviv区比例-XX:SurvivorRatio=8(Eden:S0:S1=8:1:1)
-XX:+PrintGCDetails打印详细GC日志

八、实战案例
8.1 内存泄漏排查

步骤

  1. 使用jps获取进程ID
  2. jmap -dump:format=b,file=heap.bin <pid> 导出堆快照
  3. 用MAT(Memory Analyzer Tool)分析
  4. 查找支配树中的大对象

常见原因

  • 静态集合类持有对象引用
  • 未关闭的数据库连接
  • 监听器未注销
8.2 GC优化案例

问题现象:Full GC频繁,每次耗时2秒
分析步骤

  1. jstat -gcutil <pid> 1000 发现老年代快速填满
  2. jmap -histo <pid> 发现大量相同类实例
  3. 检查代码发现缓存未设置上限
    解决方案:改用LRU缓存,限制最大条目数

九、JVM发展前沿
9.1 GraalVM
  • 多语言支持:Java、JavaScript、Python等
  • 原生镜像(Native Image):提前编译为本地可执行文件
  • 示例native-image -jar myapp.jar
9.2 Project Loom
  • 虚拟线程(Virtual Threads):轻量级线程,支持百万级并发
  • 示例
  • Thread.startVirtualThread(() -> {System.out.println("Hello from virtual thread!");
    });
    
    9.3 ZGC与Shenandoah
  • 亚毫秒级停顿:适用于金融交易系统
  • 配置示例
  • java -XX:+UseZGC -Xmx16g -XX:+UseLargePages MyApp
    

相关文章:

JVM 深度解析

一、JVM 概述 1.1 什么是 JVM&#xff1f; JVM&#xff08;Java Virtual Machine&#xff0c;Java 虚拟机&#xff09;是 Java 程序运行的核心引擎。它像一个“翻译官”&#xff0c;将 Java 字节码转换为机器能理解的指令&#xff0c;并管理程序运行时的内存、线程等资源。 …...

新能源汽车移动充电服务:如何通过智能调度提升充电桩可用率?

随着新能源汽车的普及&#xff0c;充电需求激增&#xff0c;但固定充电桩的布局难以满足用户灵活补能的需求&#xff0c;尤其在高峰时段或偏远地区&#xff0c;"充电难"问题日益凸显。移动充电服务作为新兴解决方案&#xff0c;通过动态调度充电资源&#xff0c;有望…...

SpringCloud Alibaba微服务-- Sentinel的使用(笔记)

雪崩问题&#xff1a; 小问题引发大问题&#xff0c;小服务出现故障&#xff0c;处理不当&#xff0c;可能导致整个微服务宕机。 假如商品服务出故障&#xff0c;购物车调用该服务&#xff0c;则可能出现处理时间过长&#xff0c;如果一秒几十个请求&#xff0c;那么处理时间过…...

PARSCALE:大语言模型的第三种扩展范式

----->更多内容&#xff0c;请移步“鲁班秘笈”&#xff01;&#xff01;<----- 随着人工智能技术的飞速发展&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为推动机器智能向通用人工智能&#xff08;AGI&#xff09;迈进的核心驱动力。然而&#xff0c;传统的…...

在Windows上,将 Ubuntu WSL 安装并迁移到 D 盘完整教程(含 Appx 安装与迁移导入)

&#x1f4bb; 将 Ubuntu WSL 安装并迁移到 D 盘完整教程&#xff08;含 Appx 安装与迁移导入&#xff09; 本文记录如何在 Windows 系统中手动启用 WSL、下载 Ubuntu 安装包、安装并迁移 Ubuntu 到 D 盘&#xff0c;避免默认写入 C 盘&#xff0c;提高系统性能与可维护性。 ✅…...

企微获取会话内容,RSA 解密函数

企微获取会话内容&#xff0c;RSA 解密函数 企微获取会话内容下载SDKSDK配置解密过程解密代码参考SDK文件上传到服务器最后 企微获取会话内容 官方文档&#xff1a; https://developer.work.weixin.qq.com/document/path/91774 下载SDK 根据自己的环境下载对应的SDK。 SDK配置…...

MyBatis入门:快速搭建数据库操作框架 + 增删改查(CRUD)

一、创建Mybatis的项目 Mybatis 是⼀个持久层框架, 具体的数据存储和数据操作还是在MySQL中操作的, 所以需要添加MySQL驱动 1.添加依赖 或者 手动添加依赖 <!--Mybatis 依赖包--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactI…...

离线安装Microsoft 照片【笔记】

实验环境为&#xff1a;Windows 10 企业版 LTSC。 1.下载好相关离线依赖包和安装包。 2.管理员身份运行powershell&#xff0c;输入以下命令行&#xff1a; Add-AppPackage .\Microsoft.UI.Xaml.2.4_2.42007.9001.0_x64__8wekyb3d8bbwe.Appx Add-AppPackage .\Microsoft.NET…...

地理卷积神经网络加权回归模型的详细实现方案

以下为地理卷积神经网络加权回归模型的详细实现方案。由于篇幅限制,代码和说明将分模块呈现。 地理卷积神经网络加权回归模型实现 目录 理论基础数据预处理模型架构设计空间权重矩阵生成混合模型实现实验与结果分析优化与扩展结论一、理论基础 1.1 地理加权回归(GWR) 地理…...

【后端高阶面经:Elasticsearch篇】39、Elasticsearch 查询性能优化:分页、冷热分离与 JVM 调优

一、索引设计优化:构建高效查询的基石 (一)分片与副本的黄金配置 1. 分片数量计算模型 # 分片数计算公式(单分片建议30-50GB) def calculate_shards(total_data_gb, single_shard_gb=30):return max...

光伏电站及时巡检:守护清洁能源的“生命线”

在“双碳”目标驱动下&#xff0c;光伏电站作为清洁能源的主力军&#xff0c;正以年均20%以上的装机增速重塑全球能源格局。然而&#xff0c;这些遍布荒漠、屋顶的“光伏矩阵”并非一劳永逸的能源提款机&#xff0c;其稳定运行高度依赖精细化的巡检维护。山东枣庄触电事故、衢州…...

基于 ZU49DR FPGA 的无线电射频数据采样转换开发平台核心板

无线电射频数据采样转换开发板及配套开发平台的核心板&#xff0c;该SOM核心板是一个最小系统&#xff0c;包括AMD公司的 Zynq UltraScale RFSOC 第3代系列XCZU49DR-2FFVF1760I FPGA、时钟、电源、内存以及 Flash。与其配套的底板是标准的全高全长Gen4.0 x8的PCIE卡&#xff0c…...

软考 系统架构设计师系列知识点之杂项集萃(69)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;68&#xff09; 第114题 若对关系R(A&#xff0c;B&#xff0c;C&#xff0c;D)和S(C&#xff0c;D&#xff0c;E)进行关系代数运算&#xff0c;则表达式 与&#xff08;&#xff09;等价。 A.…...

从源码编译支持ffmpeg(H264编码)的opencv(创建mp4视频报错:H264 is not supported with codec id 28)

目录 步骤 1&#xff1a;安装 FFmpeg 在 Ubuntu 上安装 FFmpeg 在 Windows 上安装 FFmpeg 验证FFmpeg是否支持H264编码 步骤 3&#xff1a;克隆 OpenCV 源码 步骤 4&#xff1a;编译 步骤 5&#xff1a;验证安装 本人的配置如下&#xff1a; 系统&#xff1a;Ubuntu 18…...

leetcode 83和84 Remove Duplicates from Sorted List 和leetcode 1836

目录 83. Remove Duplicates from Sorted List 82. Remove Duplicates from Sorted List II 1836. Remove Duplicates From an Unsorted Linked List 删除链表中的结点合集 83. Remove Duplicates from Sorted List 代码&#xff1a; /*** Definition for singly-linked l…...

每日leetcode(昨天赶飞机没做,今天补)

896. 单调数列 - 力扣&#xff08;LeetCode&#xff09; 题目 如果数组是单调递增或单调递减的&#xff0c;那么它是 单调 的。 如果对于所有 i < j&#xff0c;nums[i] < nums[j]&#xff0c;那么数组 nums 是单调递增的。 如果对于所有 i < j&#xff0c;nums[i]…...

SDL2常用函数:SDL_BlitSurfaceSDL_UpdateWindowSurface 数据结构及使用介绍

SDL_BlitSurface SDL_BlitSurface 是 SDL 1.2/2.0 中都存在的函数&#xff0c;用于将一个表面(Surface)的内容复制到另一个表面&#xff0c;支持部分复制、格式转换和简单的混合操作。 核心功能 表面复制&#xff1a;将源表面的像素数据复制到目标表面区域选择&#xff1a;可…...

【LeetCode 热题 100】买卖股票的最佳时机 / 跳跃游戏 / 划分字母区间

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;LeetCode 热题 100 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 买卖股票的最佳时机跳跃游戏跳跃游戏 II划分字母区间 买卖股票的最佳时机 买卖股票的最佳时机 class Solution { pu…...

万亿参数背后的算力密码:大模型训练的分布式架构与自动化运维全解析

目录 一、技术融合的时代背景 二、深度学习在 AI 大模型中的核心作用 2.1 预训练与微调机制 2.2 多模态深度学习的突破 三、分布式计算&#xff1a;大模型训练的基础设施 3.1 分布式训练核心原理 3.2 数据并行实战&#xff08;PyTorch DDP&#xff09; 3.3 模型并行与混…...

LangChain03-图数据库与LangGraph

图数据库与LangGraph集成实践 1. 引言 在构建智能问答系统、推荐引擎或复杂决策流程时&#xff0c;传统的关系型数据库和向量数据库往往难以满足对实体关系建模和多跳推理的需求。图数据库&#xff08;如 Neo4j、TigerGraph&#xff09;通过节点-边-属性的结构化表示&#xff…...

rabbitmq单机多实例部署

RabbitMQ 单实例部署 单实例部署是指在一台服务器上运行一个 RabbitMQ 实例。这种部署方式适用于小型应用或开发环境,配置简单,资源占用较少。单实例部署的核心是安装 RabbitMQ 并启动服务,通常需要配置 Erlang 环境,因为 RabbitMQ 是基于 Erlang 编写的。单实例部署的优势…...

Linux10正式版发布,拥抱AI了!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 作者&#xff1a;IT邦德 中国DBA联盟(ACDU)成员&#xff0c;10余年DBA工作经验 Oracle、PostgreSQL ACE CSDN博客专家及B站知名UP主&#xff0c;全网粉丝10万 擅长主流Oracle、MySQL、PG、高斯…...

在离线 OpenEuler-22.03 服务器上升级 OpenSSH 的完整指南

当然可以&#xff01;以下是一篇结构清晰、语言通俗易懂的技术博客草稿&#xff0c;供你参考和使用&#xff1a; 在离线 OpenEuler-22.03 服务器上升级 OpenSSH 的完整指南 背景介绍 最近在对一台内网的 OpenEuler-22.03 服务器进行安全扫描时&#xff0c;发现其 SSH 版本存在…...

全能邮箱全能邮箱:实现邮件管理的自动化!

全能邮箱全能邮箱&#xff1a;实现邮件管理的自动化&#xff01; 全能邮箱全能邮箱的配置教程&#xff1f;如何注册烽火域名邮箱&#xff1f; 全能邮箱全能邮箱作为一种创新的邮件管理解决方案&#xff0c;正逐渐改变我们处理邮件的方式。蜂邮EDM将围绕全能邮箱全能邮箱&…...

[特殊字符] Linux 日志查看与分析常用命令全攻略

在日常运维与开发排查中&#xff0c;我们经常需要查看服务日志来定位问题。本文系统整理了几种常用的日志查看命令&#xff0c;包括 tail、cat、grep、split、sed 等&#xff0c;并结合实际应用场景&#xff0c;提供了完整的使用方式和示例。 &#x1f4cc; 一、tail 命令 ——…...

mysql-tpcc-mysql压测工具使用

在Linux系统上安装和配置tpcc-mysql进行MySQL的TPC-C基准测试&#xff0c;通常涉及以下几个步骤。请注意&#xff0c;由于tpcc-mysql不是一个官方工具&#xff0c;它可能需要从第三方仓库获取&#xff0c;如Percona提供的版本。 前置条件 确保MySQL或MariaDB已安装&#xff1…...

Qt找不到windows API报错:error: LNK2019: 无法解析的外部符号 __imp_OpenClipboard

笔者在开发中出现的bug完整报错如下&#xff1a; spcm_ostools_win.obj:-1: error: LNK2019: 无法解析的外部符号 __imp_OpenClipboard&#xff0c;函数 "void __cdecl spcmdrv::vCopyToClipboard(char const *,unsigned __int64)" (?vCopyToClipboardspcmdrvYAXPE…...

机试 | vector/array Minimum Glutton C++

题目地址 &#xff1a; C - Minimum Glutton #include<stdio.h> #include<iostream> #include<vector> #include<algorithm> using namespace std; int main() {//N:菜肴数&#xff0c;X&#xff1a;总甜度阈值&#xff0c;Y&#xff1a;总咸度阈值int…...

OpenCv高阶(十七)——dlib库安装、dlib人脸检测

文章目录 前言一、dlib库简介二、dlib库安装1、本地安装&#xff08;离线&#xff09;2、线上安装 三、dlib人脸检测原理1、HOG 特征提取2、 SVM 分类器训练3、 滑动窗口搜索4、非极大值抑制&#xff08;NMS&#xff09; 四、dlib人脸检测代码1、导入OpenCV计算机视觉库和dlib机…...

前端内容黑白处理、轮播图、奇妙的头像特效

1、内容黑白处理 &#xff08;1&#xff09;filter&#xff1a;滤镜 可以把包裹的区域中每一个像素点&#xff0c;经过固定的算法转换成另一种颜色来呈现 &#xff08;2&#xff09;grayscale&#xff1a;灰阶滤镜 取值范围&#xff1a;0~1取0&#xff1a;原图去1&#xff…...