HotSpot JVM 启动参数

背景 本文汇总 OpenJDK HotSpot 常用启动参数(-、-X、-XX)。这些开关 不是 JVM 规范的一部分,其他实现(OpenJ9 等)名称与语义可能不同。 JVM 生态选型见 jvm;HotSpot 架构索引见 hotspot。GC 算法细节见 java-gc;JIT 与分层编译见 hotspot-jit。 参数分类 HotSpot 命令行参数分三类: 类型 前缀 说明 标准参数 - 规范要求所有实现支持,如 -version 非标准参数 -X 实现相关,如 -Xms、-Xmx;不保证跨版本兼容 不稳定参数 -XX HotSpot 专有调优项,可能无预警变更或移除 查看当前生效的 HotSpot 参数: java -XX:+PrintCommandLineFlags -version java -XX:+PrintFlagsFinal -version | grep -i gc 堆与元空间 堆大小 参数 别名 说明 -Xms<size> -XX:InitialHeapSize 初始堆大小;常与 -Xmx 设相同,避免运行期扩堆 -Xmx<size> -XX:MaxHeapSize 最大堆大小 -Xmn<size> -XX:NewSize 等 年轻代大小(eden + 2×survivor);显式设置会干扰 G1 等区域自适应,现代应用更常用比例或交给 G1 自动调整 <size> 可用 k/m/g(如 -Xmx2g)。 ...

Created 19196-06-19 · Updated 15156-07-15 · 3 min · 442 words · -

Java ASM 与运行时字节码织入

背景 BTrace、Arthas、Spring LTW、部分 AOP 框架都会在不改变业务源码的前提下改写字节码。底层常依赖 ASM(或其它字节码库)配合 JVM 的 java.lang.instrument API。 本文说明 ASM 做什么、运行时织入怎么走,以及与 Attach API / Agent 的关系。BTrace 的 attach 与脚本下发见 BTrace。概念总图见 Java 领域知识关系图。ClassLoader 可见性见 java classloader。 JLS 与 java.lang.instrument 分别指什么 JLS(Java Language Specification):Java 语言规范,定义语法、类型、可见性等;不规定 Agent 怎么 attach。 java.lang.instrument:JDK 里的标准 API 包,定义 Instrumentation、ClassFileTransformer,以及 Agent 入口约定(premain / agentmain 的方法签名、manifest 的 Premain-Class / Agent-Class)。 日常说「走 instrument 机制」= 用这套 API + JVM 内置实现,在类加载或 retransform 时回调你的 transformer。 Agent 框架定义了什么、解决什么问题 Agent 不是一个限制能力的沙箱,而是一套标准钩子 + 能力接口: 约定 / 能力 作用 manifest Agent-Class / Premain-Class 告诉 JVM 加载 agent 后调用哪个类的哪个入口 agentmain / premain + Instrumentation 在 JVM 启动后或 attach 后执行你的初始化逻辑 ClassFileTransformer 在类字节码进入 JVM 前(或 retransform 时)允许你替换字节码 Attach API loadAgent 运行中的 JVM 也能挂上 agent 要解决的问题:在不重启、不改磁盘上已部署 jar 的前提下,对已在内存中的类做字节码级增强(监控、诊断、部分场景下的热修复)。 ...

Created 15156-12-15 · Updated 30306-06-30 · 3 min · 580 words · -

Java ClassLoader

概述 不同 JVM 实现细节各异,下文只讨论 HotSpot 在 JDK 9 及以后(含当前 JDK 26)的行为。JDK 8 及更早的 ExtClassLoader、jre/lib/ext、sun.misc.Launcher 等表述见文末「JDK 8 及更早」。 本文从四方面展开:内置 ClassLoader 层次、双亲委托、自定义 ClassLoader、打破双亲委托的常见场景。类加载器「去哪里找类」由 classpath / module path 决定,概念见 Java Classpath 与 Module Path。 内置 ClassLoader 层次 JDK 运行时提供三个内置加载器(ClassLoader 官方文档): 加载器 获取方式 职责 Bootstrap Java 代码中为 null 加载 java.base 等核心模块;C++ 实现,不是 ClassLoader 子类 Platform(原 Extension) ClassLoader.getPlatformClassLoader() 加载 Java SE 平台 API 及其模块(非应用 classpath) System / Application ClassLoader.getSystemClassLoader() 加载应用 classpath、module path 上的类 父子关系: Bootstrap (null) └── PlatformClassLoader └── AppClassLoader (System ClassLoader) 实现类位于 jdk.internal.loader.ClassLoaders(PlatformClassLoader、AppClassLoader),均为内部 BuiltinClassLoader 体系。不要依赖具体类名写业务逻辑。 ...

Created 9096-09-09 · Updated 28286-06-28 · 3 min · 550 words · -

java -cp / -classpath

作用 -cp 与 -classpath 等价,用来指定运行时查找类和 JAR 的 classpath(类路径)。classpath 的概念、与依赖管理工具和 module path 的关系,见 Java Classpath 与 Module Path。 语法 java -cp <类路径> <主类全限定名> [应用参数...] 条目之间的分隔符:Linux/macOS 用冒号 :,Windows 用分号 ; 条目可以是目录或 JAR/ZIP 文件 . 代表当前目录 支持通配符 lib/*(匹配目录下所有 JAR,不递归子目录),但不能写 lib/*.jar 一旦显式指定 -cp,默认的当前目录 . 不再自动加入,需要时要显式写上 示例 # 当前目录 + 一个 jar(Linux/macOS) java -cp .:lib/hsqldb.jar org.hsqldb.Server -database mydb # Windows 用分号分隔 java -cp .;lib\hsqldb.jar org.hsqldb.Server -database mydb # 用通配符引入一个目录下所有 jar java -cp "app.jar:lib/*" com.example.Main 现在大多用 Maven/Gradle 或 IDE 自动拼装 classpath,手写 -cp 多见于命令行手动编译运行、排查问题等场景。 ...

Created 17176-04-17 · Updated 28286-06-28 · 1 min · 87 words · -

Java ClassLoader (merged into classloader)

本文已合并 这篇 2012 年的转载内容(基于 JDK 8 的 ExtClassLoader、sun.misc.Launcher、jre/lib/ext 等)已过时,相关内容已并入并按 JDK 9+ / 当前 HotSpot 重写: 类加载器层次、双亲委托、自定义 ClassLoader、打破双亲委托:见 Java ClassLoader classpath / module path 概念:见 Java Classpath 与 Module Path 本页仅作旧链接(/p4316/、java-classloader-2)重定向占位保留。 维护记录 时间 修改内容 原因 2026-06-28 退役为重定向占位,正文并入 classloader.md;新增 classpath 概念链到 classpath.md;分类 Java→language,删除 reprint 与现行 HotSpot 不符、与 classloader.md 高度重复

Created 26266-09-26 · Updated 28286-06-28 · 1 min · 47 words · lcf

Java Classpath 与 Module Path

Classpath 是什么 Classpath(类路径) 是 JVM 在运行时查找 .class 文件和 JAR 包的搜索路径集合。当代码里出现 new Foo() 或 Foo.class 时,类加载器要把 com.example.Foo 这个名字解析成磁盘上的 com/example/Foo.class 字节码,去哪里找,就由 classpath 决定。 可以把它理解成「类的 PATH 环境变量」:shell 的 PATH 决定 ls、git 这些命令去哪些目录找可执行文件;JVM 的 classpath 决定加载类时去哪些目录和 JAR 里找字节码。 一条 classpath 由多个条目组成,每个条目是一个目录或一个 JAR/ZIP 文件: 目录条目:以该目录为根,按包名展开找 .class(如条目 target/classes + 类 com.foo.Bar → 找 target/classes/com/foo/Bar.class) JAR 条目:把 JAR 当成一个打包的目录,在其中按同样规则找 分隔符与操作系统有关:Linux/macOS 用冒号 :,Windows 用分号 ;。 如何设置 classpath 按优先级从高到低,常见几种方式: 方式 写法 说明 -cp / -classpath java -cp app.jar:lib/* com.foo.Main 命令行显式指定,最常用;详见 java -cp CLASSPATH 环境变量 export CLASSPATH=... 全局生效,易污染,现代项目基本不用 可执行 JAR 的 Class-Path MANIFEST.MF 里的 Class-Path: JAR 内清单声明依赖;见 MANIFEST.MF 默认值 不指定时为当前目录 . 仅在没有任何设置时 -cp 支持通配符 lib/*(匹配该目录下所有 JAR,但不递归子目录),但不能写成 lib/*.jar。指定了 -cp 后默认的当前目录 . 会失效,需要的话要显式写进去。 ...

Created 28286-06-28 · Updated 28286-06-28 · 2 min · 295 words · -

GraalVM

是什么 GraalVM 是 Oracle 主导的 高性能 JDK 发行版与工具链,基于 OpenJDK,但不止「又一个 Temurin」:它在同一产品里组合了 Java 运行时、Graal JIT 编译器、Native Image AOT、Truffle 多语言运行时 等能力。 日常讨论里常把 GraalVM 缩略成「Native Image 用的那个 JDK」,实际上 Native Image 只是其组件之一;完整图景见下文与 Java 虚拟机 生态对照。 发行版 版本 说明 Community Edition (CE) 开源(GPLv2 + Classpath exception),GitHub 发布 Enterprise Edition (EE) 商业支持,额外性能与工具(需 Oracle 许可) 安装后通常提供 java、javac、native-image、gu(GraalVM Updater,用于安装/管理组件)等命令。具体组件集因版本与安装方式而异。 三种常见使用方式 GraalVM 发行版 │ ┌─────────────────────┼─────────────────────┐ ▼ ▼ ▼ JVM 模式(java) Native Image Truffle / Polyglot HotSpot + Graal JIT AOT 本地二进制 JS/Python/Ruby 等同 JVM 上互操作 │ │ │ └── 见专文 └── 仍跑 .class,可替代默认 C2 路径(视版本与 -XX 开关) 1. JVM 模式:Graal 作 JIT 用 GraalVM 自带的 java 跑字节码,底层仍是 HotSpot VM,但可用 Graal 编译器 作为 JIT 替代或补充传统 C1/C2(取决于 JDK 版本与 JVM 参数;OpenJDK 曾实验性集成 Graal JIT,JDK 17+ 默认路径以 C2 为主,Graal JIT 需显式启用或视发行版而定)。 ...

Created 21216-06-21 · Updated 21216-06-21 · 2 min · 341 words · -

java.lang.Class类

说明 java.lang.Class 的说明已整理至专文:java.lang.Class。 本文保留 url java-class-object 以兼容旧链接。 维护记录 时间 修改内容 原因 2026-06-21 正文删去,改为指向 lang-class.md 与 Class 专文去重

Created 2026-01-02 · Updated 21216-06-21 · 1 min · 17 words · -

Class.forName

Class.forName 是获取 java.lang.Class 对象的一种方式:用字符串形式的完全限定类名在运行时查找并加载类。类名来自配置、用户输入或 JDBC 驱动名等场景时,通常走这条路径。 API 形式 // 等价于 forName(name, true, 当前 ClassLoader) Class<?> clazz = Class.forName("com.example.Foo"); // 显式控制是否初始化、使用哪个 ClassLoader Class<?> clazz = Class.forName("com.example.Foo", false, classLoader); 第二个参数 initialize: true:加载后执行类初始化(静态代码块、静态字段赋值等) false:只加载并链接,暂不初始化 单参数 Class.forName(name) 相当于 initialize = true。 与 .class、getClass() 的区别 方式 类名来源 默认是否初始化 Foo.class 编译期写死 否 obj.getClass() 已有实例 否 Class.forName("Foo") 运行期字符串 是 Class 对象本身的含义、唯一性等见专文 java.lang.Class。 典型用途 JDBC 驱动加载(历史写法) 早期 JDBC 常用 Class.forName 触发驱动类静态块,向 DriverManager 注册: Class.forName("com.mysql.cj.jdbc.Driver"); Connection conn = DriverManager.getConnection(url, user, password); 驱动类静态块执行即可完成注册,一般不必再 newInstance()。现代 JDBC 4+ 驱动多通过 SPI 自动加载,此写法已较少见,但有助于理解 forName 与类初始化的关系。 ...

Created 21216-12-21 · Updated 21216-06-21 · 1 min · 127 words · -

java.lang.Class

java.lang.Class 是 JVM 为每一种 Java 类型在运行时维护的元信息对象。它不代表某个业务实例,而是代表类型本身——类、接口、枚举、注解类型、数组、基本类型乃至 void 都有对应的 Class 实例。 反射、注解 读取、框架扫描等能力,都依赖先拿到正确的 Class 对象。 Class 与实例的区别 实例对象 Class 对象 含义 某个类的具体对象 描述类型本身的元数据 示例 new SampleSubject() SampleSubject.class 数量 可创建多个实例 每种类型在 JVM 中唯一 SampleSubject a = new SampleSubject(); SampleSubject b = new SampleSubject(); a.getClass() == SampleSubject.class; // true a.getClass() == b.getClass(); // true:同一类型的 Class 只有一个 a == b; // false:实例不同 何时创建、由谁创建 Class 没有 public 构造方法,不能 new Class()。对象在类加载过程中由 JVM 通过类加载器的 defineClass 等机制创建。加载流程见 java classloader。 ...

Created 21216-06-21 · Updated 21216-06-21 · 2 min · 264 words · -

Java 诊断工具 BTrace

背景 本文记录的是 JDK 8 生产环境下的实践:线上出现问题时,在不改代码、不重启的前提下,用 BTrace attach 到运行中的 JVM,按条件过滤慢方法并持续输出。 BTrace 概念与相关文章的关系见 Java 领域知识关系图。 何时需要 BTrace(生产动机) 动机 说明 不能停机 滚动重启成本高或 SLA 不允许 保留故障现场 重启后偶现问题、特定请求参数、堆内对象态、当时流量下的慢调用往往 难以复现;需要在 故障仍在发生时 对当前 JVM 取样 观测而非热修 BTrace 用于 慢调用过滤、参数、耗时、调用路径 等可观测数据,不是用 agent 临时改业务逻辑修 Bug(机制上 agent 能改字节码,但 BTrace 产品侧用脚本校验限制为安全探针) 车联网协议解析 G4 因写 MySQL 偏慢导致 OOM、后迁移 InfluxDB 的完整案例见 物联网平台协议解析服务生产环境 OOM:MySQL 迁移 InfluxDB(职业叙事;本文偏工具用法)。 临时排查可配合 生产环境诊断工具选型(Arthas、JFR 等);BTrace 适合 脚本化、持续输出 的采集。 安装 BTrace 不是单个原生二进制,而是 Java 工具发行包(压缩包 + shell 脚本 + JAR),运行时依赖本机 JDK。 从 GitHub Releases 下载 btrace-bin.tar.gz 或 .zip,解压后大致结构: ...

Created 2026-06-02 · Updated 31316-05-31 · 6 min · 1146 words · -

Java Attach API

背景 JDK 8 生产排查里,BTrace、jcmd 等工具都需要在 不重启业务 JVM 的前提下与之交互。底层机制是 JDK 自带的 Attach API(com.sun.tools.attach,jdk.attach 模块):一个本地进程通过 PID 连上目标 HotSpot JVM,再在这条 attach 通道上发送不同种类的请求。 Attach 不是只有 loadAgent 一种用法。jcmd 的 Thread.print、JFR.start 等走 JVM 内置 Diagnostic Command,一般 不需要 再加载外部 agent JAR;BTrace 等才典型地 loadAgent。 本文说明 Attach 通道、公开 API、与 jcmd / BTrace 的关系。概念总图见 Java 领域知识关系图。容器、新版 JDK 注意点见文末。 是什么 Attach 让已启动的 HotSpot JVM 在运行中被另一进程「挂上」: 连接入口:VirtualMachine.attach(pid)(及 AttachProvider 发现 JVM) 通道上可发多种 attach 操作(见下节),不限于 loadAgent 其中一类操作会加载外部 Agent JAR,调用 agentmain(启动时 -javaagent 则走 premain) 不是远程 RPC:必须在本机(或共享进程命名空间,见文末),且一般要求与目标 JVM 相同的有效用户/组。 ...

Created 30306-05-30 · Updated 31316-05-31 · 3 min · 618 words · -

开发期热替换(HotSwap、DCEVM、HotSwapAgent)

背景 开发时希望改 Java 代码后 少重启 就能看到效果。这与生产上 BTrace attach 观测 不是同一条路。本文归纳 HotSwap 及相关工具,并说明各自边界。 字节码织入与 redefine 机制见 java-asm;调试协议见 JPDA、JVMTI。 HotSwap 是什么 HotSwap(热替换)泛指:不重启整个 JVM,把 已在内存中的类 换成新字节码。 HotSpot 自带 的热替换能力很窄(通过 调试器 触发,底层 JVMTI / redefine): 常见成功:改 已有方法的方法体 常见失败:新增方法/字段、改签名、改继承、新 import 等 因此 IDE 在 Debug 下保存后提示 “Hot swap” 成功或失败,依赖的是 JPDA → JDWP → JVMTI,不是 Attach API 加载 BTrace agent 那条栈。 开发期 HotSwap(典型) IDE 编译 .class → JDWP 命令 → JVM redefine 已加载类 生产期 BTrace(对比) loadAgent → Instrumentation + ASM retransform → 插探针(观测) 几种开发期方案 方案 怎么做 能力边界 IDE HotSwap Debug + JPDA 方法体为主,标准 HotSpot 最严 JRebel 商业 agent 类加载/字节码策略更激进,需授权 DCEVM 替换/并行使用 修改版 HotSpot(-XXaltjvm=dcevm) 放宽 redefine:可加删方法/字段等 HotSwapAgent -javaagent:hotswapagent.jar + 常配合 DCEVM 用 Javassist 改字节码;插件重载 Spring/Hibernate 等配置 Spring Boot DevTools 双 ClassLoader 快速 Restart 重建 Spring 上下文,不是 JVM 级 HotSwap Spring DevTools 细节见 Spring Boot DevTools。 ...

Created 17176-12-17 · Updated 31316-05-31 · 2 min · 224 words · -

JVMTI(Java 虚拟机工具接口)

背景 调试器断点、IDE 热替换、jcmd 部分能力、Attach API 的 loadAgentLibrary、native agent,底层都依赖 JVM 提供的 native 级 工具接口。在 HotSpot/OpenJDK 上,这一层主要是 JVMTI。 JVMTI 是什么 JVMTI(Java Virtual Machine Tool Interface)是 JVM 实现的 C 语言 native 接口(jvmti.h),用于: 调试:断点、单步、查看栈与局部变量 分析:采样、分配追踪 类与字节码:监听类加载、重定义已加载类(与 IDE HotSwap 相关) Agent:native agent 在 Agent_OnLoad 里通过 JavaVM::GetEnv 拿到 jvmtiEnv 它 不是 Java 应用直接 import 的包;Java 侧看到的是更高层的封装。 前身(已淘汰) 用途 JVMDI 调试 JVMPI 性能分析 JDK 5+ 由 JVMTI 统一替代(见 JPDA 文中的历史说明)。 与 JPDA、Instrumentation 的关系 IDE / jdb(调试器) ↓ JDI(Java API) ↓ JDWP(线协议,如 dt_socket) ↓ JVMTI Agent(如 jdwp.so)→ JVMTI 调用 ↓ HotSpot JVM java.lang.instrument(Java Agent,premain/agentmain) ↓ JVM 内部同样依赖 JVMTI 等 native 能力实现 redefine/retransform 接口 语言 典型用途 JVMTI C / native 调试器后端、profiler、native agent JPDA(JDI + JDWP + JVMTI) 调试体系 Eclipse/IDEA 远程调试、JDB java.lang.instrument Java BTrace、Arthas、-javaagent、部分 APM 三者都落在 同一 JVM 进程 里,但入口不同:写 Java 诊断 agent 用 instrument + Attach;写调试器走 JPDA;写 native 库 agent 用 JVMTI + loadAgentLibrary。 ...

Created 31316-05-31 · Updated 31316-05-31 · 1 min · 195 words · -

jcmd

背景 本文记录 JDK 8 生产环境下的用法:在主机上查看正在运行的 Java 进程 PID,并向目标 JVM 发送诊断命令(线程栈、堆 dump、JVM 参数等)。常与 BTrace attach 前配合使用(jcmd -l 列进程)。 New Features in JDK7 update 4 JRockit command line utility JRCMD (JRockit Command). JRCMD was a command line tool to enumerate the Java processes running on the local machine, and to send commands (referred to as “Diagnostic Commands”) to them. JRCMD has been renamed JCMD (Java Command). jcmd 用于向正在运行的 JVM 发送诊断信息请求,从 JDK 1.7 开始提供,可以说是 jstack 和 jps 的结合体。 ...

Created 6066-02-06 · Updated 30306-05-30 · 3 min · 589 words · -

Java 生产环境诊断工具选型

背景 生产环境曾运行在 JDK 8。线上出现问题时,用 BTrace attach 到运行中的 JVM:按条件过滤慢方法(例如耗时超过 9ms),持续输出,不改代码、不重启。 当时 JFR 仍是商业特性,attach 式动态追踪是可行且低成本的方案之一。本文先记录 JDK 8 时代的诉求与 BTrace 用法,其它 JDK 版本下的工具对照见文末章节。 JDK 8 时代 BTrace 在解决什么 从 BTrace 使用笔记 中的脚本可以看出,核心需求是: attach 到运行中的 JVM,不重启 按条件过滤慢方法(例如大于 9ms) 持续输出,而不是只看一次快照 必要时查看参数、返回值、调用栈 示例脚本(慢调用过滤 + 计数): @OnMethod(clazz = "com.wiloon.package0.Class0", method = "method0", location = @Location(Kind.RETURN)) public static void printMethodRunTime(@ProbeClassName String probeClassName, @Duration long duration) { long d = duration / 1000000; if (d > 9) { i++; println("index: " + i + ", timestamp:" + timestamp("HH:mm:ss") + ", " + probeClassName + ", duration: " + d + " ms"); } } 执行方式: ...

Created 30306-05-30 · Updated 30306-05-30 · 2 min · 415 words · -