IDEA 点击运行后的流程
.java 文件 --javac--> .class 文件 --java--> 执行
(源代码) (编译) (字节码) (运行) (程序)
java 是用来运行 .class 文件的,所以在用 java 之前,需要先用 javac 编译。
好好学习,天天向上
.java 文件 --javac--> .class 文件 --java--> 执行
(源代码) (编译) (字节码) (运行) (程序)
java 是用来运行 .class 文件的,所以在用 java 之前,需要先用 javac 编译。
.java 文件 --javac--> .class 文件 --java--> 执行
(源代码) (编译) (字节码) (运行) (程序)
javac:编译器,将 .java 源文件编译成 .class 字节码java:运行器,启动 JVM 加载并执行 .class 文件┌─────────────────────────────────────────┐
│ JDK │
│ ┌────────────────────────────────────┐ │
│ │ JRE │ │
│ │ ┌────────────────────────────────┐│ │
│ │ │ JVM ││ │
│ │ │ (Java Virtual Machine) ││ │
│ │ │ - 加载 .class ││ │
│ │ │ - 执行字节码 ││ │
│ │ └────────────────────────────────┘│ │
│ │ + 核心类库 (rt.jar) │ │
│ │ - java.lang.* │ │
│ │ - java.util.* │ │
│ └────────────────────────────────────┘ │
│ + 开发工具 │
│ - javac (编译器) │
│ - java (运行器) │
│ - javadoc (文档生成) │
│ - jdb (调试器) │
│ - jmap, jstack (性能分析) │
└─────────────────────────────────────────┘
垃圾收集算法是理论基础,定义了如何识别和回收垃圾;垃圾收集器是算法的具体实现,一个收集器可以实现一种或多种算法
JVM 的垃圾收集器主要分为两大类:分代收集器和分区收集器
分代收集器的代表是 CMS
分区收集器的代表是 G1 和 ZGC
分代是按对象年龄划分(新生代/老年代),针对性回收;分区是把堆切成独立小区域(Region),可预测停顿时间。
现代收集器(如 G1)结合两者:逻辑上分代,物理上分区。
ZGC 是 JDK 11 时引入的一款低延迟的垃圾收集器,最大特点是将垃圾收集的停顿时间控制在 10ms 以内,即使在 TB 级别的堆内存下也能保持较低的停顿时间。
ZGC 也采⽤了复制算法,只不过做了重⼤优化,ZGC 在标记、转移和重定位阶段⼏乎都是并发的,这是 ZGC 实现停顿时间⼩于 10ms 的关键所在
关键技术
JVM 的操作对象是 Class 文件。JVM 把 Class 文件中描述类的数据结构加载到内存中,并对数据进行校验、解析和初始化,最终转化成可以被 JVM 直接使用的类型,这个过程被称为类加载机制。
类加载是运行时进行的,JVM 不会在启动时加载所有类,而是按需加载。
触发类加载的时机(主动引用):
new一个对象- 访问类的静态变量或静态方法
- 使用反射(如
Class.forName())- 初始化子类时(会先触发父类加载)
不触发类加载的情况(被动引用):
- 通过子类引用父类的静态变量
- 定义类数组(如
MyClass[] arr)- 常量引用(如
MyClass.CONST)
类加载器是在运行时动态决定的,不是编译时指定的。
当你写 new MyClass() 时,JVM 会使用定义当前类的同一个 ClassLoader去加载 MyClass。
所以如果你想让某个类用自定义 ClassLoader 加载,有两种方式:
// 创建自定义类加载器
MyClassLoader classLoader = new MyClassLoader();
// 用它加载类(返回 Class<?>,不能用强类型)
Class<?> clazz = classLoader.loadClass("com.example.MyClass");
// 用反射创建实例
Object obj = clazz.newInstance();
屏障 = 在某个操作前后插入的"检查点"或"钩子"
想象一个小区门禁:
居民进出 → [门禁屏障] → 记录谁进出了 → 放行
屏障不做"拦截",只做"记录"或"检查"
CPU 为了性能会重排序指令,内存屏障告诉 CPU:
指令1
指令2
[内存屏障] ← barrier 之前的指令必须先执行完
指令3
指令4
对象的内存布局是由 Java 虚拟机规范定义的,但具体的实现细节各有不同,如 HotSpot 和 OpenJ9 就不一样
常用的 HotSpot 为例:
对象在内存中包括三部分:对象头、实例数据和对齐填充
对象头 (Mark World + 类型指针 (指向 Class 对象)) + 实例数据 + 对齐填充
对象头 (8字节 + 8字节 (压缩 4 字节)): 12字节 (指针压缩)
对齐填充必须是 8 的倍数 (64位)