一、JVM概述
Java假造机(Java Virtual Machine,JVM)是Java平台的焦点组件,它负责实行编译后的Java字节码,提供了内存管理、垃圾回收、安全控制等关键功能。JVM的"一次编写,到处运行"(Write Once, Run Anywhere)特性使得Java成为跨平台开发的范例。
1.1 JVM的焦点价值
- 平台无关性:字节码可以在任何实现了JVM规范的平台上运行
- 自动内存管理:提供垃圾回收机制,淘汰内存泄漏风险
- 安全沙箱:通过字节码验证和安全管理器提供安全实行情况
- 优化实行:包含即时编译器(JIT)提升实行效率
1.2 JVM规范与实现
- 规范:由Oracle发布的官方文档(JSR规范)
- 主要实现:
- HotSpot(Oracle官方实现,最广泛利用)
- OpenJ9(IBM/Eclipse实现,资源占用低)
- GraalVM(支持多语言的高性能VM)
- Android Runtime(ART,Android专用)
二、JVM整体架构
JVM的完整架构可分为四个主要子体系:
- 类加载子体系(Class Loader Subsystem)
- 运行时数据区(Runtime Data Areas)
- 实行引擎(Execution Engine)
- 本地方法接口(JNI)与本地库
三、类加载子体系
3.1 类加载过程
类加载子体系负责加载、链接和初始化类文件,主要分为三个阶段:
3.1.1 加载(Loading)
- 通过类的全限定名获取类的二进制字节流
- 将字节流所代表的静态存储布局转换为方法区的运行时数据布局
- 在堆中生成代表该类的Class对象,作为方法区数据的访问入口
3.1.2 链接(Linking)
验证(Verification):
- 文件格式验证(魔数0xCAFEBABE)
- 元数据验证(语义分析)
- 字节码验证(栈映射帧)
- 符号引用验证
准备(Preparation):
- 为类变量(static变量)分配内存
- 设置默认初始值(0、false、null等)
解析(Resolution):
3.1.3 初始化(Initialization)
- 实行类构造器<clinit>()方法
- 该方法由编译器自动收集类中所有类变量的赋值动作和静态代码块合并产生
3.2 类加载器体系
JVM采用双亲委派模子的条理化类加载机制:
3.2.1 启动类加载器(Bootstrap ClassLoader)
- 由C++实现,是JVM的一部分
- 加载<JAVA_HOME>/lib目次下的焦点类库
- 是唯一没有父加载器的加载器
3.2.2 扩展类加载器(Extension ClassLoader)
- Java实现,继承自java.lang.ClassLoader
- 加载<JAVA_HOME>/lib/ext目次下的类
- 父加载器为Bootstrap
3.2.3 应用程序类加载器(Application ClassLoader)
- 也称为体系类加载器(System ClassLoader)
- 加载用户类路径(ClassPath)上的类
- 父加载器为Extension
3.2.4 自界说类加载器
开发者可以继承java.lang.ClassLoader实现自己的类加载器,典型应用场景:
- 热摆设(如Tomcat)
- 代码加密/解密
- 模块化加载
- // 自定义类加载器示例
- public class CustomClassLoader extends ClassLoader {
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- byte[] classData = loadClassData(name); // 自定义加载逻辑
- return defineClass(name, classData, 0, classData.length);
- }
-
- private byte[] loadClassData(String className) {
- // 实现从特定位置加载类文件的逻辑
- }
- }
复制代码 3.3 双亲委派模子工作原理
- 类加载请求起首委派给父加载器
- 只有当父加载器无法完成加载时,子加载器才会实验加载
- 所有加载请求最终都会传递到启动类加载器
优势:
- 制止类的重复加载
- 防止焦点API被篡改(安全思量)
破坏双亲委派的场景:
- SPI机制(如JDBC)
- OSGi模块化体系
- 热摆设需求
四、运行时数据区
4.1 程序计数器(PC Register)
- 线程私有,生命周期与线程相同
- 记录当前线程实行的字节码指令地址
- 实行Native方法时值为undefined
- 唯一不会出现OOM的内存区域
4.2 Java假造机栈(Java Virtual Machine Stacks)
- 线程私有,生命周期与线程相同
- 存储栈帧(Stack Frame),每个方法调用对应一个栈帧
- 大概抛出StackOverflowError(栈深度凌驾限定)和OutOfMemoryError(扩展时无法申请足够内存)
栈帧布局:
- 局部变量表(Local Variable Table)
- 存储方法参数和局部变量
- 以Slot为最小单位(32位)
- 操纵数栈(Operand Stack)
- 动态链接(Dynamic Linking)
- 方法返回地址(Return Address)
- 附加信息(可选)
4.3 本地方法栈(Native Method Stack)
- 为Native方法服务
- 大概抛出StackOverflowError和OutOfMemoryError
- HotSpot将Java假造机栈和本地方法栈合二为一
4.4 Java堆(Java Heap)
- 线程共享,假造机启动时创建
- 存储对象实例和数组
- GC管理的主要区域
- 可分为新生代(Young Generation)和老年代(Old Generation)
分代计划:
- 新生代:
- 老年代:长期存活的对象
- 元空间(Java 8+):类元数据(取代永久代)
4.5 方法区(Method Area)
- 线程共享,存储已被加载的:
- Java 8后由元空间(Metaspace)实现,利用本地内存
运行时常量池:
- 方法区的一部分
- 存储编译期生成的字面量和符号引用
- 具备动态性(运行时可将新常量放入池中)
五、实行引擎
5.1 解释器(Interpreter)
- 逐条读取、解释和实行字节码
- 启动速度快,实行效率较低
- HotSpot包含模板解释器和C++解释器
5.2 即时编译器(JIT Compiler)
工作原理:
- 监控热点代码(Hot Spot)
- 将字节码编译为本地机器码
- 优化并缓存编译结果
HotSpot中的JIT编译器:
- C1编译器(Client Compiler):
- C2编译器(Server Compiler):
- 分层编译(Tiered Compilation):
常见的JIT优化技术:
- 方法内联(Method Inlining)
- 逃逸分析(Escape Analysis)
- 锁消除(Lock Elision)
- 循环展开(Loop Unrolling)
5.3 垃圾收集器(Garbage Collector)
详见本系列垃圾回收专题文章,主要收集器包括:
- Serial/Serial Old
- ParNew
- Parallel Scavenge/Parallel Old
- CMS
- G1
- ZGC
- Shenandoah
六、本地方法接口(JNI)
6.1 JNI的作用
- 提供Java调用本地方法(C/C++)的能力
- 允许本地代码调用Java功能
- 实现跨平台与高性能盘算
6.2 典型应用场景
- 体系级功能调用
- 遗留代码集成
- 性能关键代码优化
- 硬件设备访问
- public class NativeExample {
- // 声明本地方法
- public native void nativeMethod();
-
- // 加载本地库
- static {
- System.loadLibrary("NativeLibrary");
- }
-
- public static void main(String[] args) {
- new NativeExample().nativeMethod();
- }
- }
复制代码 对应C++实现:
- #include <jni.h>
- #include <iostream>
- #include "NativeExample.h"
- JNIEXPORT void JNICALL Java_NativeExample_nativeMethod(JNIEnv *env, jobject obj) {
- std::cout << "Native method called!" << std::endl;
- }
复制代码 七、JVM内存模子(JMM)
7.1 主内存与工作内存
- 主内存:存储共享变量
- 工作内存:线程私有,存储线程操纵变量的副本
7.2 内存间交互操纵
- lock(锁定)
- unlock(解锁)
- read(读取)
- load(载入)
- use(利用)
- assign(赋值)
- store(存储)
- write(写入)
7.3 volatile的特殊规则
7.4 happens-before原则
- 程序顺序规则
- 锁规则
- volatile规则
- 线程启动规则
- 线程终止规则
- 线程停止规则
- 对象终结规则
- 传递性
八、JVM优化技术
8.1 逃逸分析
- 栈上分配:对象不逃逸时可分配在栈上
- 标量更换:将对象分解为基本范例字段
- 同步消除:去除不大概竞争的锁
8.2 内联优化
- 将小方法直接嵌入调用处
- 淘汰方法调用开销
- 为其他优化创造条件
8.3 公共子表达式消除
- 辨认并消除重复盘算
- 局部公共子表达式消除
- 全局公共子表达式消除
九、JVM监控与调优
9.1 常用监控工具
- 命令行工具:
- jps:JVM进程状态
- jstat:JVM统计监测
- jinfo:配置信息
- jmap:内存映像
- jstack:堆栈跟踪
- 可视化工具:
- JConsole
- VisualVM
- Java Mission Control
- Arthas(阿里开源)
9.2 关键性能指标
9.3 调优原则
- 优先满意业务需求而非追求理论最优
- 先收集数据再优化,制止盲目调优
- 小步调解,每次只改一个参数
- 关注瓶颈,80%的性能题目通常由20%的代码引起
十、JVM的发展与将来
10.1 Java各版本的JVM演进
- Java 8:引入Metaspace,移除永久代
- Java 9:模块化体系影响类加载
- Java 11:引入ZGC(实验性)
- Java 14:移除CMS
- Java 15:ZGC和Shenandoah转正
- Java 17:LTS版本,进一步优化GC
10.2 新兴技术趋势
- AOT编译(GraalVM Native Image)
- 值范例(Valhalla项目)
- 协程(Loom项目)
- 新一代GC算法(如Epsilon GC)
十一、总结
JVM作为Java技术的基石,其复杂而精妙的计划支撑了Java生态的繁荣发展。从类加载机制到内存管理,从实行引擎到垃圾回收,每个子体系都表现了盘算机科学的经典理论与工程实践的完美连合。
深入明白JVM架构不仅有助于:
- 编写更高效的Java代码
- 进行有用的性能调优
- 诊断息争决运行时题目
- 计划高并发的可靠体系
随着Java语言的持续演进,JVM也在不绝创新,引入更多先进特性和优化技术。作为Java开发者,持续关注和学习JVM的最新发展,将使我们能够更好地驾御这个强大的平台,构建更出色的应用体系。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |