我把示例代码放了一份在 Github 上,jol-samples,想看的同学可以 clone 下来把每个 example 跑一跑就能看到 JVM 对象在内存中布局的一些信息,包括对象头占多大、字节怎么对齐、字段在内存中的顺序不一定与声明的顺序一致、涉及到继承时字段是如何存放的、带 transient
修饰符的字段被特殊处理、Java8 新增的 @Contended
注解的作用、JVM 的平台相关性、对象头中的 mark word 及 class word、轻量锁、偏向锁、重量锁、Hashcode、GC 需要用到的对象引用图、哈希碰撞时转换为链表以及 Java8 中极端情况下转换为红黑树、观察 mark word 中的 age 字段的值在 GC 后的变化 等等,我没有一个一个写出来,因为 25 个例子太多了,设计到的知识点也比较多,需要一些前置知识才能理解。
JOL (Java Object Layout) is the tiny toolbox to analyze object layout schemes in JVMs. These tools are using Unsafe, JVMTI, and Serviceability Agent (SA) heavily to decoder the actual object layout, footprint, and references. This makes JOL much more accurate than other tools relying on heap dumps, specification assumptions, etc.
以下是在看到输出后可能会迷惑的地方:
- 首先要明确输出是大端字节序还是小端字节序,将二进制转换为十进制与后面的数字比较下就能确定。
- 伪共享、缓存一致性以及 Java8 中的
@Contended
注解,可能需要参考 False Sharing, Cache Coherence, and the @Contended Annotation on the Java 8 VM 及 深入理解Java虚拟机(第2版)。 - Java8 中 HashMap 的变化,可参考 Java 8 HashMaps, Keys and the Comparable interface。
- 涉及到对象头的部分可能需要参考这篇文章,Java Object header,需要找到和你运行时 JVM 对应的平台相关的对象头来看,比如我在本地运行时是 64 位的 HotSpot JVM,就需要看最下面的基于 64 位的对象头。