zoukankan      html  css  js  c++  java
  • 对象头是个什么东东?

      对象头,顾名思义,就是对象的头。对象是实例化出来的,实例化的前提是必须有类这个模板。举个不大恰当的例子,人类就是个类,你我他就是人类实例化出来的对象。我们的头,自然就是对象头。我们的头有口鼻眼耳,对象头也有一些东西,主要包含两部分:Mark Word(标记字)和Class Pointer(类指针),如果是数组对象还得再加一项Array Length(数组长度)。

      对象头为啥要有这些东东?Mark Word用来标记运行时信息(每个对象各不相同),Class Pointer用来指向生成该对象所在的类(认祖归宗),Array Length告诉我们数组的长度。后两项简单易懂,最复杂的是这个Mark Word了,看下JVM的markWord.hpp是怎么规定它的:

    // The markWord describes the header of an object.
    //
    // Bit-format of an object header (most significant first, big endian layout below):
    //
    //
    32 bits: // -------- // hash:25 ------------>| age:4 biased_lock:1 lock:2 (normal object) // JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object) // // 64 bits: // -------- // unused:25 hash:31 -->| unused_gap:1 age:4 biased_lock:1 lock:2 (normal object) // JavaThread*:54 epoch:2 unused_gap:1 age:4 biased_lock:1 lock:2 (biased object)

      它说markWord描述了对象头,采用大端点表示,markWord包含了哈希码(hash)、GC分代年龄(age)、偏向锁(biased_lock)、锁状态(lock)和用来滥竽充数的间隔位(64位里那些unused开头的字段)。32位和64位机器存储这些东东的位大小各不相同。如果对象不再是普通对象(normal object),变成了一个偏向锁(biased object),那么markWord所含内容的哈希码就变成了持有锁的线程指针(JavaThread*)、偏向时间戳(epoch),其他不变。

      最后再说这个锁状态:

    //  - the two lock bits are used to describe three states: locked/unlocked and monitor.
    //
    //    [ptr             | 00]  locked             ptr points to real header on stack
    //    [header      | 0 | 01]  unlocked           regular object header
    //    [ptr             | 10]  monitor            inflated lock (header is wapped out)
    //    [ptr             | 11]  marked             used to mark an object

      00——轻量锁,存储内容是栈帧中指向锁对象的指针(ptr

      01——无锁,至于是否偏向锁,需要再往前一位看,0:无锁,1:偏向锁。至于所存储之物,上面已提到:如果是普通对象(0),存储内容就是上哈希码GC分代年龄;若是偏向锁(1),则是拥有锁的线程指针偏向时间戳对象分代年龄

      10——监视器锁(moniter),也就是重量锁,存储内容为指向锁对象的指针(ptr

      11——GC标记

      好了,理论说完,下面举例说明:

      1、pom.xml新增jar包:

            <dependency>
                <groupId>org.openjdk.jol</groupId>
                <artifactId>jol-core</artifactId>
                <version>0.14</version>
            </dependency>

      2、新增测试类:

    import com.wlf.springcloudgateway.javabean.HelloWorld;
    import org.openjdk.jol.info.ClassLayout;
    
    import java.util.concurrent.TimeUnit;
    
    public class ObjectMarkWord {
    
        public static void main(String[] args) throws InterruptedException {
    
            // 实例化对象
            HelloWorld helloWorld = HelloWorld.builder().name("wlf").build();
    
            // 1、普通对象,无锁
            System.out.println("普通对象:");
            printfObjMarkWord(helloWorld);
    
            // 2、实例化数组,打印数组对象信息,无锁
            System.out.println("数组对象:");
            String[] address = new String[]{"hangzhou", "nanjing", "shenzhen"};
            printfObjMarkWord(address);
    
    
            // 3、单线程首次加锁,轻量锁
            System.out.println("轻量锁:");
            new Thread(() -> {
                synchronized (helloWorld) {
                    printfObjMarkWord(helloWorld);
                }
            }).start();
    
            TimeUnit.SECONDS.sleep(2);
    
            // 4、多个线程加锁,升级重量锁
            System.out.println("重量锁:");
            for (int i = 0; i < 2; i++) {
                new Thread(() -> {
                    synchronized (helloWorld) {
                        printfObjMarkWord(helloWorld);
                    }
                }).start();
            }
        }
    
        private static void printfObjMarkWord(Object obj) {
            System.out.println("-------------------------");
            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
            System.out.println("-------------------------");
    
        }
    
    }
    import lombok.Data;
    
    @Data
    @Builder
    public class HelloWorld {
        private String name;
    }

      在跑之前给IDEA去掉指针压缩(jdk8默认开启):Run -> Edit Configurations -> VM:options那一栏加上-XX:-UseCompressedOops

      输出结果:

    普通对象:
    -------------------------
    com.wlf.springcloudgateway.javabean.HelloWorld object internals:
     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)                           88 49 0e 17 (10001000 01001001 00001110 00010111) (386812296)
         12     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
         16     8   java.lang.String HelloWorld.name                           (object)
    Instance size: 24 bytes
    Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
    
    -------------------------
    数组对象:
    -------------------------
    [Ljava.lang.String; object internals:
     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)                           20 e9 dd 16 (00100000 11101001 11011101 00010110) (383641888)
         12     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
         16     4                    (object header)                           03 00 00 00 (00000011 00000000 00000000 00000000) (3)
         20     4                    (alignment/padding gap)                  
         24    24   java.lang.String String;.<elements>                        N/A
    Instance size: 48 bytes
    Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
    
    -------------------------
    轻量锁:
    -------------------------
    com.wlf.springcloudgateway.javabean.HelloWorld object internals:
     OFFSET  SIZE               TYPE DESCRIPTION                               VALUE
          0     4                    (object header)                           60 f4 05 1a (01100000 11110100 00000101 00011010) (436597856)
          4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
          8     4                    (object header)                           88 49 0e 17 (10001000 01001001 00001110 00010111) (386812296)
         12     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
         16     8   java.lang.String HelloWorld.name                           (object)
    Instance size: 24 bytes
    Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
    
    -------------------------
    重量锁:
    -------------------------
    com.wlf.springcloudgateway.javabean.HelloWorld object internals:
     OFFSET  SIZE               TYPE DESCRIPTION                               VALUE
          0     4                    (object header)                           ca da 66 17 (11001010 11011010 01100110 00010111) (392616650)
          4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
          8     4                    (object header)                           88 49 0e 17 (10001000 01001001 00001110 00010111) (386812296)
         12     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
         16     8   java.lang.String HelloWorld.name                           (object)
    Instance size: 24 bytes
    Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
    
    -------------------------
    -------------------------
    com.wlf.springcloudgateway.javabean.HelloWorld object internals:
     OFFSET  SIZE               TYPE DESCRIPTION                               VALUE
          0     4                    (object header)                           ca da 66 17 (11001010 11011010 01100110 00010111) (392616650)
          4     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
          8     4                    (object header)                           88 49 0e 17 (10001000 01001001 00001110 00010111) (386812296)
         12     4                    (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
         16     8   java.lang.String HelloWorld.name                           (object)
    Instance size: 24 bytes
    Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
    
    -------------------------
    
    Process finished with exit code 0

      我本机是64位的,所以markWord、class pointer、array length都是8字节:

      

      有锁、无锁,看标黄的00、01,是否偏向锁,看标红的那一位。同一个对象的class pointer是一致的,从标黄处也能看出来。普通对象是无锁(01)的,首次加锁后变成了轻量锁(00,为啥不是偏向锁?参见)。接着再另起两个线程竞争锁,原来的轻量锁膨胀为重量锁。这里有个问题:为啥偏向锁没有出来冒泡?答案参见偏向锁是个什么东东? 

  • 相关阅读:
    Visual Studio 出现生成错误 ,要继续并运行上次的成功生成吗?
    postgresql迁mysql之后兼容性问题
    Java中把十进制转为二进制(判断有效的ip地址和掩码)
    Java中如何把整数变为二进制输出
    Java二进制与十进制转换及位运算
    面试知识点总结之开放性问题
    面试知识点总结之常用设计模式
    linux下VIRT,RES,SHR的含义
    JSP JS 日期控件的下载、使用及注意事项
    Html5实现头像上传和编辑,保存为Base64的图片过程
  • 原文地址:https://www.cnblogs.com/wuxun1997/p/14075463.html
Copyright © 2011-2022 走看看