首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >JAVA对象布局之对象头(Object Header)

JAVA对象布局之对象头(Object Header)

原创
作者头像
Java宝典
修改于 2020-12-04 09:03:25
修改于 2020-12-04 09:03:25
1.7K00
代码可运行
举报
运行总次数:0
代码可运行

由于Java面向对象的思想,在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能 。在学习并发编程知识synchronized时,我们总是难以理解其实现原理,因为偏向锁、轻量级锁、重量级锁都涉及到对象头,所以了解java对象头是我们深入了解synchronized的前提条件,以下我们使用64位JDK示例

1.对象布局的总体结构

2.获取一个对象布局实例

1.首先在maven项目中 引入查看对象布局的神器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>

2.调用ClassLayout.parseInstance().toPrintable()

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Main{
    public static void main(String[] args) throws InterruptedException {
        L l = new L();  //new 一个对象 
        System.out.println(ClassLayout.parseInstance(l).toPrintable());//输出 l对象 的布局
    }
}
//对象类
class L{
    private boolean myboolean = true;
}

运行后输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4           (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4           (object header)                           f0 e4 2c 11 (11110000 11100100 00101100 00010001) (288154864)
     12     4           (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
     16     1   boolean L.myboolean                               true
     17     7           (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 7 bytes external = 7 bytes total

对象头所占用的内存大小为16*8bit=128bit。如果大家自己动手去打印输出,可能得到的结果是96bit,这是因为我关闭了指针压缩。jdk8版本是默认开启指针压缩的,可以通过配置vm参数关闭指针压缩。关于更多压缩指针访问JAVA文档:官网

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
关闭指针压缩        -XX:-UseCompressedOops

开启指针压缩之后,再看对象的内存布局:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4           (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4           (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     1   boolean L.myboolean                               true
     13     3           (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total
  • OFFSET:偏移地址,单位字节;
  • SIZE:占用的内存大小,单位为字节;
  • TYPE DESCRIPTION:类型描述,其中object header为对象头;
  • VALUE:对应内存中当前存储的值;

开启指针压缩可以减少对象的内存使用。因此,开启指针压缩,理论上来讲,大约能节省百分之五十的内存。jdk8及以后版本已经默认开启指针压缩,无需配置。

普通的对象获取到的对象头结构为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
|--------------------------------------------------------------|
|                     Object Header (128 bits)                 |
|------------------------------------|-------------------------|
|        Mark Word (64 bits)         | Klass pointer (64 bits) |
|------------------------------------|-------------------------|

普通对象压缩后获取结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
|--------------------------------------------------------------|
|                     Object Header (96 bits)                  |
|------------------------------------|-------------------------|
|        Mark Word (64 bits)         | Klass pointer (32 bits) |
|------------------------------------|-------------------------|

数组对象获取到的对象头结构为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
|---------------------------------------------------------------------------------|
|                                 Object Header (128 bits)                        |
|--------------------------------|-----------------------|------------------------|
|        Mark Word(64bits)       | Klass pointer(32bits) |  array length(32bits)  |
|--------------------------------|-----------------------|------------------------|
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)
     12     4        (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
     16    20    int [I.<elements>                             N/A
     36     4        (loss due to the next object alignment)
Instance size: 40 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

3.对象头的组成

我们先了解一下,一个JAVA对象的存储结构。在Hotspot虚拟机中,对象在内存中的存储布局分为 3 块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding) 在我们刚刚打印的结果中可以这样归类:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)    //markword             01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4           (object header)    //markword             00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4           (object header)   //klass pointer 类元数据 43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     1   boolean L.myboolean                               true    // Instance Data 对象实际的数据
     13     3           (loss due to the next object alignment)            //Padding 对齐填充数据
1.Mark Word

这部分主要用来存储对象自身的运行时数据,如hashcode、gc分代年龄等。mark word的位长度为JVM的一个Word大小,也就是说32位JVM的Mark word为32位,64位JVM为64位。为了让一个字大小存储更多的信息,JVM将字的最低两个位设置为标记位,不同标记位下的Mark Word示意如下:

其中各部分的含义如下:lock:2位的锁状态标记位,由于希望用尽可能少的二进制位表示尽可能多的信息,所以设置了lock标记。该标记的值不同,整个mark word表示的含义不同。通过倒数三位数 我们可以判断出锁的类型

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
enum {  locked_value                 = 0, // 0 00 轻量级锁
         unlocked_value           = 1,// 0 01 无锁
         monitor_value            = 2,// 0 10 重量级锁
         marked_value             = 3,// 0 11 gc标志
         biased_lock_pattern      = 5 // 1 01 偏向锁
  };
通过内存信息分析锁状态

写一个synchronized加锁的demo分析锁状态 接着,我们再看一下,使用synchronized加锁情况下对象的内存信息,通过对象头分析锁状态。

代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Main{
    public static void main(String[] args) throws InterruptedException {
        L l = new L();
        Runnable RUNNABLE = () -> {
            while (!Thread.interrupted()) {
                synchronized (l) {
                    String SPLITE_STR = "===========================================";
                    System.out.println(SPLITE_STR);
                    System.out.println(ClassLayout.parseInstance(l).toPrintable());
                    System.out.println(SPLITE_STR);
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        for (int i = 0; i < 3; i++) {
            new Thread(RUNNABLE).start();
        }
    }
}

class L{
    private boolean myboolean = true;
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
===========================================
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           5a 97 02 c1 (01011010 10010111 00000010 11000001) (-1056794790)
      4     4           (object header)                           d7 7f 00 00 (11010111 01111111 00000000 00000000) (32727)
      8     4           (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     1   boolean L.myboolean                               true
     13     3           (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total

===========================================

Mark Word为0X00007FD7C102975A 对应的2进制为: 0xb00000000 00000000 01111111 11010111 11000001 00000010 10010111 01011010 我们可以看到在第一行object header中 value=5a 对应的2进制为01011010 倒数第三位 为0表示不是偏量锁,后两位为10表示为重量锁

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
enum {  locked_value                 = 0, // 0 00 轻量级锁
         unlocked_value           = 1,// 0 01 无锁
         monitor_value            = 2,// 0 10 重量级锁
         marked_value             = 3,// 0 11 gc标志
         biased_lock_pattern      = 5 // 1 01 偏向锁
  };

例子2:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Main{
    public static void main(String[] args) throws InterruptedException {
        L l = new L();
        synchronized (l) {
            Thread.sleep(1000);
            System.out.println(ClassLayout.parseInstance(l).toPrintable());
            Thread.sleep(1000);
        }     //轻量锁
    }
}

class L{
    private boolean myboolean = true;
}

输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           f0 18 58 00 (11110000 00011000 01011000 00000000) (5773552)
      4     4           (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
      8     4           (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     1   boolean L.myboolean                               true
     13     3           (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 3 bytes external = 3 bytes total

对应的mark word为0x00007000005818f0 对应的2进制为0xb00000000 00000000 01110000 00000000 00000000 01011000 00011000 11110000 根据末尾倒数第三位为0 表示不是偏量锁 倒数后2位为00 表示这是一个轻量锁

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
enum {  locked_value                 = 0, // 0 00 轻量级锁
         unlocked_value           = 1,// 0 01 无锁
         monitor_value            = 2,// 0 10 重量级锁
         marked_value             = 3,// 0 11 gc标志
         biased_lock_pattern      = 5 // 1 01 偏向锁
  };

你可能会有疑问mark word = 0x00007000005818f0是怎么算出来的, 根据前64位的value倒序排列拼成的串就是mark word 例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 OFFSET  SIZE      TYPE DESCRIPTION                               VALUE
      0     4           (object header)                           f0 18 58 00 (11110000 00011000 01011000 00000000) (5773552)
      4     4           (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
      8     4           (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     1   boolean L.myboolean                               true
     13     3           (loss due to the next object alignment)

Mark word 串为 前64位倒序排列为:00000000 00000000 01110000 00000000 00000000 01011000 00011000 11110000 转换为16进制为 00007000005818f0

2.Klass Pointer

即对象指向它的元数据的指针,虚拟机通过这个指针来确定是哪个类的实例。并不是所有的虚拟机实现都必须在对象数据上保留类型指针(通过句柄池访问)。

简单引申一下对象的访问方式,我们创建对象的目的就是为了使用它。所以我们的Java程序在运行时会通过虚拟机栈中本地变量表的reference数据来操作堆上对象。但是reference只是JVM中规范的一个指向对象的引用,那这个引用如何去定位到具体的对象呢?因此,不同的虚拟机可以实现不同的定位方式。主要有两种:句柄池和直接指针。

2.1 使用句柄访问

会在堆中开辟一块内存作为句柄池,句柄中储存了对象实例数据(属性值结构体)的内存地址,访问类型数据的内存地址(类信息,方法类型信息),对象实例数据一般也在heap中开辟,类型数据一般储存在方法区中。

优点:reference存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要改变。缺点:增加了一次指针定位的时间开销。

2.2 使用指针访问

指针访问方式指reference中直接储存对象在heap中的内存地址,但对应的类型数据访问地址需要在实例中存储。

优点:节省了一次指针定位的开销。缺点:在对象被移动时(如进行GC后的内存重新排列),reference本身需要被修改。

总结:

通过句柄池访问的话,对象的类型指针是不需要存在于对象头中的,但是目前大部分的虚拟机实现都是采用直接指针方式访问。此外如果对象为JAVA数组的话,那么在对象头中还会存在一部分数据来标识数组长度,否则JVM可以查看普通对象的元数据信息就可以知道其大小,看数组对象却不行

3. 对齐填充字节

因为JVM要求java的对象占的内存大小应该是8bit的倍数,所以后面有几个字节用于把对象的大小补齐至8bit的倍数,就不特别介绍了

4.JVM升级锁的过程

1,当没有被当成锁时,这就是一个普通的对象,Mark Word记录对象的HashCode,锁标志位是01,是否偏向锁那一位是0。

2,当对象被当做同步锁并有一个线程A抢到了锁时,锁标志位还是01,但是否偏向锁那一位改成1,前23bit记录抢到锁的线程id,表示进入偏向锁状态。

3,当线程A再次试图来获得锁时,JVM发现同步锁对象的标志位是01,是否偏向锁是1,也就是偏向状态,Mark Word中记录的线程id就是线程A自己的id,表示线程A已经获得了这个偏向锁,可以执行同步锁的代码。

4,当线程B试图获得这个锁时,JVM发现同步锁处于偏向状态,但是Mark Word中的线程id记录的不是B,那么线程B会先用CAS操作试图获得锁,这里的获得锁操作是有可能成功的,因为线程A一般不会自动释放偏向锁。如果抢锁成功,就把Mark Word里的线程id改为线程B的id,代表线程B获得了这个偏向锁,可以执行同步锁代码。如果抢锁失败,则继续执行步骤5。

5,偏向锁状态抢锁失败,代表当前锁有一定的竞争,偏向锁将升级为轻量级锁。JVM会在当前线程的线程栈中开辟一块单独的空间,里面保存指向对象锁Mark Word的指针,同时在对象锁Mark Word中保存指向这片空间的指针。上述两个保存操作都是CAS操作,如果保存成功,代表线程抢到了同步锁,就把Mark Word中的锁标志位改成00,可以执行同步锁代码。如果保存失败,表示抢锁失败,竞争太激烈,继续执行步骤6。

6,轻量级锁抢锁失败,JVM会使用自旋锁,自旋锁不是一个锁状态,只是代表不断的重试,尝试抢锁。从JDK1.7开始,自旋锁默认启用,自旋次数由JVM决定。如果抢锁成功则执行同步锁代码,如果失败则继续执行步骤7。

7,自旋锁重试之后如果抢锁依然失败,同步锁会升级至重量级锁,锁标志位改为10。在这个状态下,未抢到锁的线程都会被阻塞。

总结:本章节主要介绍了对象布局包含对象头,对象实例数据,和对齐数据.并且介绍了对象头中包含的信息和解析方法 更多内容请持续关注公众号:java宝典

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
怎么创建 JavaScript 自定义事件
你肯定处理过很多的事件监听,比如点击事件或者表单提交。事件监听对许多用例来说很有帮助,但是有时我们需要创建自己的自定义事件来处理复杂的交互。在这片短文中,我将告诉你有关创建自定义事件,侦听自定义事件以及创建双击自定义事件所要了解的内容。
Jimmy_is_jimmy
2022/04/29
1.5K0
怎么创建 JavaScript 自定义事件
🔥JavaScript 自定义事件如此简单!
在前端开发世界中,JavaScript 和 HTML 之间往往通过 事件 来实现交互。其中多数为内置事件,本文主要介绍 JS自定义事件概念和实现方式,并结合案例详细分析自定义事件的原理、功能、应用及注意事项。
pingan8787
2020/02/22
1.7K0
盘点原生JavaScript中直接触发事件的方式
JavaScript提供了多种方式来直接触发事件,无论是在用户交互、程序逻辑处理或是数据更新时。本文将全面探讨原生JavaScript中各种事件触发方式,并通过深入的技术案例分析,帮助开发者掌握这些方法在实际开发中的应用。
李游Leo
2025/01/21
2470
盘点原生JavaScript中直接触发事件的方式
【JS】2029- 如何创建 JavaScript 自定义事件?
假设,你正在构建一个复杂的 web 应用程序,你想到了可以预构建例如click和submit这样的事件,这很好,但如果你需要更特殊一点怎么办?
pingan8787
2024/04/30
3730
【JS】2029- 如何创建 JavaScript 自定义事件?
实现一个 EventEmitter 类
在前端开发中,经常会使用到发布订阅模式,发布订阅模式也被称为观察者模式。最常见的发布订阅模式莫过于给 DOM 绑定事件,当点击一个按钮或者鼠标移动到某个元素上就会触发事件监听函数,然后弹出一个文本框或者改变元素样式。
多云转晴
2020/05/28
1.4K0
详解JavaScript事件处理程序
事件是用户与浏览器进行交互的方式。譬如用户点击按钮就会产生click事件,浏览器会找到相应js代码并执行,我们要做的就是按照规则编写js代码放在指定位置即可。
Learn-anything.cn
2021/12/26
9960
JavaScript 自定义事件的实现
自定义事件,就是有别于有别于带有浏览器特定行为的事件(类似 click, mouseover, submit, keydown 等事件),事件名称可以随意定义,可以通过特定的方法进行添加,触发以及删除。
逆葵
2019/04/25
8670
浅谈JavaScript的事件(事件模拟)
  事件经常由操作或者通过浏览器功能触发,通过JavaScript也可以触发元素的事件。通过JavaScript触发事件,也称为事件的模拟。 DOM中事件模拟   可以document的createEvent方法创建event对象。这个方法接收一个参数,即表示要创建的事件类型的字符串。在DOM2级中,所有这些字符串都使用英文复数形式,在DOM3级中都变成了单数。这几个字符串如下:UIEvents,一般化的ui事件,鼠标事件和键盘事件都继承于该事件,在DOM3级中是UIEvent;MouseEvents,一般
水击三千
2018/02/27
2.1K0
JavaScript实现HTML5长按事件监听
在现代Web开发中,触摸和手势操作变得越来越重要。长按(Long Press)作为一种常见的手势操作,广泛应用于移动端和桌面端的交互设计中。本文将详细介绍如何使用纯JavaScript实现HTML5长按事件监听,而不依赖任何第三方库。
编程小白狼
2025/04/28
3650
JavaScript事件
JavaScript事件 对于事件来讲,首先,我们需要了解这样几个概念:事件;事件处理程序;事件类型;事件流;事件冒泡;事件捕获;事件对象;事件模拟,事件方面的性能优化(事件委托、移除事件处理程序); 事件的概念 事件:指的是文档或者浏览器窗口中发生的一些特定交互瞬间。我们可以通过监听器(或者处理程序)来预定事件,以便事件发生的时候执行相应的代码。 事件处理程序:我们用户在页面中进行的点击这个动作,鼠标移动的动作,网页页面加载完成的动作等,都可以称之为事件名称,即:click、mousemove、loa
汤高
2018/01/11
2.2K0
JavaScript事件
js 事件笔记
在Web中, 事件在浏览器窗口中被触发,执行事先绑定的事件处理器(也就是事件触发时会运行的代码块),对事件做出响应。 用户在浏览器的任何一个操作都会去触发一个事件,JavaScript采用异步事件驱动编程模型,当文档、浏览器、元素或与之相关对象发生特定事情时,浏览器会产生事件。
bamboo
2019/01/29
11.7K0
js 事件笔记
Flex事件机制(二)
本文介绍了Flex事件机制,以及如何利用自定义事件在父子组件之间传递数据。首先介绍了Flex事件机制,包括Event、EventDispatcher、EventSystem、Bubbling和Capturing。然后通过一个实例,展示了如何在子组件中触发自定义事件,并通过EventDispatcher将数据传递给父组件。父组件使用EventSystem监听子组件触发的事件,然后使用dispatchEvent发送响应事件。最后,总结了使用自定义事件在父子组件之间传递数据的实现方法。
高爽
2017/12/28
6960
JS自定义事件原生
说在开始,Javascript自定义事件类似设计的观察者模式,通过状态的变更来监听行为,主要功能解耦,易于扩展。多用于组件、模块间的交互。 原型模式下的js自定义事件 var EventTarget = function() { this._listener = {}; }; EventTarget.prototype = { constructor: this, addEvent: function(type, fn) { if (typeof type =
空空云
2018/09/27
3.3K0
JS里,事件的几个细节问题--(冒泡、自定义事件)
今天想实现一个事件自动订阅到指定class的元素之上的功能。这句话很拗口,稍后解释!
申君健
2018/09/21
1.5K0
JavaScript 事件
原文链接:https://note.noxussj.top/?source=cloudtencent 鼠标事件 鼠标单击事件 click 在文档中鼠标进行单击,就会触发事件。 var i = 0 d
菜园前端
2023/05/09
8480
如何用 JavaScript 模拟点击事件,简单实现 x, y 坐标点击?
在前端开发中,有时我们需要模拟点击页面上的某个位置,比如自动化测试或者模拟用户操作。今天,我将一步步带大家实现这个功能,让大家能够轻松理解并应用。
前端达人
2024/07/20
2.9K0
如何用 JavaScript 模拟点击事件,简单实现 x, y 坐标点击?
JS事件流
HTML中与javascript交互是通过事件驱动来实现的,例如鼠标点击事件、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。
前端逗逗飞
2021/04/30
9K0
JS事件流
自定义事件
上面这种情况,当点击子组件时并不会触发handleClick()事件,因为此时的click并非原生的点击事件,而是一个自定义事件。
小小杰啊
2022/12/21
4020
3.1、我们的JSBridge
公司研发的一款服务软件App(姑且称为“大地”),提供了包涵消息、待办、工作台、同事圈和通讯录五大功能模块,其中,工作台里集成了包括公司的移动客户端、PC端以及第三方平台的部分功能/服务(统称为“应用”)。
甜点cc
2022/10/05
1.1K0
3.1、我们的JSBridge
24 个 ES6 实用方法,用来解决实际开发的 JS 问题
页面DOM里的每个节点上都有一个classList对象,程序员可以使用里面的方法新增、删除、修改节点上的CSS类。使用classList,程序员还可以用它来判断某个节点是否被赋予了某个CSS类。
Javanx
2020/03/09
8670
相关推荐
怎么创建 JavaScript 自定义事件
更多 >
LV.5
西安百搜科技工程师
目录
  • 1.对象布局的总体结构
  • 2.获取一个对象布局实例
  • 3.对象头的组成
    • 1.Mark Word
      • 通过内存信息分析锁状态
    • 2.Klass Pointer
      • 2.1 使用句柄访问
      • 2.2 使用指针访问
    • 3. 对齐填充字节
  • 4.JVM升级锁的过程
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档