JVM 02
今天是2025/03/23 19:07 day 10
总路线请移步主页Java大纲相关文章
今天进行JVM 3,4 个模块的归纳
首先是JVM的相关内容概括的思维导图
3. 类加载机制
加载过程
-
加载(Loading)
-
通过类全限定名获取类的二进制字节流(如从JAR包、网络、动态代理生成等)。
-
将字节流转化为方法区的运行时数据结构,生成
Class
对象作为访问入口。
-
-
验证(Verification)
-
文件格式验证:检查魔数、版本号等是否符合JVM规范。
-
元数据验证:语义校验(如是否有父类、是否继承final类等)。
-
字节码验证:确保代码逻辑合法(如类型转换、跳转指令)。
-
符号引用验证:确保符号引用能正确解析到目标类/方法/字段。
-
-
准备(Preparation)
-
为静态变量(static修饰)分配内存(方法区),并赋默认零值(如int=0,引用=null)。
-
若字段被
final
修饰且是基本类型/字符串常量,直接赋程序设定的初始值(无需等到初始化阶段)。
-
-
解析(Resolution)
-
将常量池中的符号引用(类、方法、字段的间接引用)替换为直接引用(内存地址偏移量)。
-
解析可能发生在初始化之前(静态绑定)或之后(动态绑定,如虚方法调用)。
-
-
初始化(Initialization)
-
执行类构造器
<clinit>()
方法,合并类中所有静态变量的赋值动作和静态代码块。 -
JVM保证父类的
<clinit>()
先于子类执行。 -
初始化是触发类加载的最终步骤(如
new
、反射调用、主类加载等)。
-
类加载器
-
启动类加载器(Bootstrap ClassLoader)
-
由C++实现,加载
JAVA_HOME/lib
下的核心类库(如rt.jar)。 -
唯一不继承
ClassLoader
的加载器,Java代码中无法直接引用。
-
-
扩展类加载器(Extension ClassLoader)
-
Java实现,加载
JAVA_HOME/lib/ext
目录的扩展类。 -
是
sun.misc.Launcher$ExtClassLoader
的实例。
-
-
应用程序类加载器(Application ClassLoader)
-
加载用户类路径(ClassPath)下的类,是默认的类加载器。
-
由
sun.misc.Launcher$AppClassLoader
实现。
-
-
自定义类加载器
-
继承
ClassLoader
类,重写findClass()
方法,实现从特定路径加载类。 -
典型场景:热部署、模块化加载、加密类文件解密。
-
双亲委派模型
-
工作原理: 子加载器收到加载请求后,先委派父加载器尝试加载,父加载器无法完成时,子加载器才自行加载。
-
优点:
-
避免类重复加载(如
java.lang.Object
只会由Bootstrap加载一次)。 -
防止核心类被篡改(自定义的
java.lang.String
不会被加载)。
-
-
打破双亲委派:
-
SPI机制(如JDBC驱动加载):使用线程上下文类加载器(TCCL)逆向委派。
-
OSGi模块化:自定义类加载器实现网状委派。
-
4. 执行引擎
解释器(Interpreter)
-
逐行解释执行字节码,无需等待编译,启动速度快。
-
适用于短生命周期或低频执行的代码(如一次性任务)。
JIT编译器(Just-In-Time)
-
C1编译器(Client Compiler)
-
轻量级优化,编译速度快,适合对启动速度敏感的应用(如GUI程序)。
-
优化手段:方法内联、去虚拟化、冗余消除。
-
-
C2编译器(Server Compiler)
-
深度优化,生成高效本地代码,适合长时间运行的服务端应用。
-
优化手段:逃逸分析、锁消除、循环展开。
-
-
分层编译(Tiered Compilation)
-
JDK7+默认策略,结合C1和C2:
-
Level 0:解释执行。
-
Level 1~3:C1编译(带基础性能监控)。
-
Level 4:C2编译(激进优化)。
-
-
通过
-XX:+TieredCompilation
启用。
-
热点代码检测
-
方法调用计数器:统计方法调用次数,触发JIT编译(阈值:Client模式1500次,Server模式10000次)。
-
回边计数器:统计循环体执行次数,触发OSR(栈上替换)编译。
-
热度衰减:计数器半衰期(
-XX:CounterHalfLifeTime
),避免长期未触发的代码占用资源。
编译优化技术
-
方法内联(Inlining)
-
将小方法(如Getter/Setter)直接嵌入调用处,减少栈帧开销。
-
受
-XX:MaxInlineSize
(默认35字节)控制。
-
-
逃逸分析(Escape Analysis)
-
判断对象是否仅在方法内部使用(未逃逸),若成立则:
-
栈上分配:对象直接在栈上分配,避免堆内存压力。
-
标量替换:将对象拆分为基本类型字段,消除对象头开销。
-
-
-
锁消除(Lock Elision)
-
基于逃逸分析,若锁对象未逃逸(线程私有),直接移除同步操作。
-
本地方法接口(JNI)
-
允许Java代码调用C/C++编写的本地方法(如
native
修饰的方法)。 -
典型场景:
-
操作系统底层操作(如文件IO)。
-
高性能计算(如矩阵运算)。
-
-
缺点:
-
破坏平台无关性。
-
JNI调用开销较大(需切换上下文)。
-
-
类加载机制通过双亲委派保障安全性和一致性,支持动态扩展(如SPI)。
-
执行引擎通过解释器与JIT编译器的协同,平衡启动速度和运行效率,结合逃逸分析等优化技术提升性能。