知其然,知其所以然
Java 内部原理 2026-10-04

Java 依赖漏洞扫描

用 mvn dependency:tree 解析 6 个直接依赖(13 个构件),再用 OSV 的 querybatch 在 2.7 秒内查出 11 个构件共 92 条已知漏洞记录(jackson-databind 2.9.8 一个就有 59 条);传递依赖里有 5 个构件带漏洞;各漏洞的 CVE、严重程度、修复版本;同一个库不同版本的记录数对比。

Java 依赖漏洞 OSV SCA Maven 传递依赖 真实验证 动画演示
Java 内部原理 2026-10-04

构建缓存与增量编译

用 Maven 3.9 与 maven-build-cache-extension 1.2.0 在一个 8 个类加 1.5 秒测试的小项目上实测:增量编译在没改东西时不重新编译但仍跑测试(2.8 秒),改一个文件会重新编译整个模块的 8 个源文件;构建缓存命中后 clean verify 只要 1.2 秒(跳过编译、测试、打包 6 个插件执行),源文件改动后未命中 3.3 秒。

Java Maven 构建缓存 增量编译 build-cache-extension 真实验证 动画演示
Java 内部原理 2026-10-04

MethodHandle 组合器:把调用逻辑组合成句柄

在 JDK 21 上逐个运行 MethodHandle 的组合器:insertArguments、dropArguments、filterArguments、filterReturnValue、permuteArguments、foldArguments、collectArguments、asSpreader、guardWithTest、catchException、tryFinally、countedLoop、asType、asVarargsCollector 的类型与结果,以及常见的类型错误;static final 句柄与直接调用一样快(0.58 ns),局部句柄 2.26 ns。

Java MethodHandle 组合器 invokedynamic java.lang.invoke 真实验证 动画演示
Java 内部原理 2026-10-04

LambdaMetafactory:运行时生成函数式实现

在 JDK 21 上验证 lambda 的实现:javac 把 lambda 体编成合成方法、使用处是 invokedynamic 加 LambdaMetafactory;非捕获 lambda 是单例、捕获的每次新建;第一个 lambda 链接 3.03 ms(-Xshare:off 时 6.42 ms);手动调用 metafactory 得到同类的隐藏类且调用耗时相同;可序列化 lambda 通过 altMetafactory 与 SerializedLambda。

Java lambda LambdaMetafactory invokedynamic 隐藏类 SerializedLambda 真实验证 动画演示
Java 内部原理 2026-10-04

ClassValue:为每个 Class 建立可回收缓存

在 JDK 21 上验证 ClassValue:每个 Class 一份缓存、computeValue 并发时被调用 8 次但只保留一个结果、取值 2.24 ns 比 ConcurrentHashMap 的 3.10 ns 更快;用自定义类加载器验证——static ConcurrentHashMap 与「值引用 key 的 WeakHashMap」会泄漏类加载器,ClassValue 即使值持有 Class 本身也不泄漏。

Java ClassValue 类加载器 缓存 内存泄漏 WeakHashMap 真实验证 动画演示
Java 内部原理 2026-10-04

Nestmates:嵌套类如何访问彼此的私有成员

在 JDK 21 上对比同一份嵌套类源码 --release 21 与 --release 8 的编译结果:release 21 没有 access$ 桥接方法、有 NestHost / NestMembers 属性,类文件更少更小(3 个 2440 字节对 4 个 2696 字节);getNestHost / getNestMembers / isNestmateOf;反射读私有字段的限制;嵌套关系不一致时的 IllegalAccessError 与旧方式的 NoSuchMethodError。

Java Nestmates 嵌套类 NestHost access$000 私有访问 真实验证 动画演示
Java 内部原理 2026-10-04

assert 断言:开发期不变量如何表达

在 JDK 21 上验证 assert:字节码里的 $assertionsDisabled 与 desiredAssertionStatus;-ea / -da / -esa 对不同包的作用;断言关闭时表达式不被求值;断言状态在类初始化时固定,之后再改无效;一个昂贵的断言开启后每次迭代 10.51 ns,关闭时 0.58 ns。

Java assert 断言 -ea AssertionError desiredAssertionStatus 真实验证 动画演示
Java 内部原理 2026-10-04

枚举 switch 的兼容性

用真实的分别编译验证枚举 switch 的兼容性:javac 生成 Client$1 与 $SwitchMap$Color(按名字映射,每个常量 try/catch NoSuchFieldError);库新增、重排、删除、重命名枚举常量时,不重新编译的客户端各种 switch 写法的行为:新增常量走 default 或抛 MatchException,删除常量不失败,直接用 ordinal() 会出错。

Java 枚举 switch 二进制兼容 SwitchMap MatchException 真实验证 动画演示
Java 内部原理 2026-10-04

JIT 内联:方法调用如何变成调用者代码

用 -XX:+PrintInlining 在 JDK 21 上验证 JIT 内联:4 / 105 / 157 / 521 字节的方法在 C1 与 C2 两次编译中的内联决定(C2 内联 105 与 157 字节的,拒绝 521 字节的 hot method too big);改 FreqInlineSize 与 -Inline 的耗时;调用点接收者 1 / 2 / 3 / 4 种类型时 0.51 / 0.69 / 3.26 / 3.24 ns。

Java JIT 内联 PrintInlining FreqInlineSize 多态 真实验证 动画演示
Java 内部原理 2026-10-04

OSR:长循环运行中如何切换到编译代码

在 JDK 21 上验证 OSR:只被调用一次的 main 里的长循环,默认每迭代 0.7 ns,关闭 OSR 后停在解释器里 26 ns(与 -Xint 的 23.6 ns 相当);PrintCompilation 里带 % 与 @bci 的 OSR 记录经历 C1 → C2 → 作废 → 再 C1 → 再 C2 两轮;嵌套循环的 OSR 入口在内层循环头。

Java OSR 栈上替换 分层编译 PrintCompilation 真实验证 动画演示
Java 内部原理 2026-10-04

元空间碎片:类元数据为什么不只看容量

在 JDK 21 / 17 上验证元空间:300 个加载器 × 150 个类时 capacity 107.61 MB、used 98.10 MB,全部丢弃后 committed 从 106.92 MB 降到 3.82 MB;同样丢弃一半加载器,交错丢弃比丢弃前一半多留 32.79 MB 已提交的空闲 chunk(虚拟空间 committed 78.81 vs 55.50 MB);JDK 21 忽略 MetaspaceReclaimPolicy,JDK 17 的 none 丢弃后 committed 不降。

Java Metaspace 元空间 类卸载 jcmd VM.metaspace 真实验证 动画演示
Java 内部原理 2026-10-04

类初始化死锁

在 JDK 21 上复现类初始化死锁:A、B 互相引用的静态初始化器,以及 Parent 持有 Child 实例的无显式环的例子;两个线程都是 RUNNABLE,ThreadMXBean 的死锁检测返回 null,线程转储里看 “waiting on the Class initialization monitor”;时间窗口小于 1 ms 时 40/40 死锁,晚 5 ms 启动则 0/40。

Java 类初始化 死锁 jstack clinit 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号