[Java]并发编程-JOL分析对象头和性能分析

[Java]并发编程-JOL分析对象头和性能分析_第1张图片

无锁 偏向锁 轻量锁 重量锁 GC
0 01 1 01 00 10 1 001
  • 前unused:25+identity_hashcode:31=56存的是hashcode

一、java对象的布局以及对象头的布局

A.java

public class A {

}

JOLExample1.java

package com.layout;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;

import static java.lang.System.out;
public class JOLExample1 {
    static  A a = new A();
    public static void main(String[] args) {
        //jvm的信息
        out.println(VM.current().details());
        out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}

# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

com.layout.A 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)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

二、验证hashcode对象头是那几位

JOLExample.java

package com.layout;
import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;

import static java.lang.System.out;
public class JOLExample1 {
    static  A a = new A();
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        //jvm的信息
        A a= new A();
        out.println("befor hash");
        //没有计算HASHCODE之前的对象头
        out.println(ClassLayout.parseInstance(a).toPrintable());
        //JVM 计算的hashcode
        out.println("jvm------------0x"+Integer.toHexString(a.hashCode()));
        HashUtil.countHash(a);
        //当计算完hashcode之后,我们可以查看对象头的信息变化
        out.println("after hash");
        out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}

befor hash
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
com.layout.A 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)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

jvm------------0x2e5c649
util‐‐‐‐‐‐‐‐‐‐‐0x2e5c649
after hash
com.layout.A object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 49 c6 e5 (00000001 01001001 11000110 11100101) (-439990015)
      4     4        (object header)                           02 00 00 00 (00000010 00000000 00000000 00000000) (2)
      8     4        (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes

[Java]并发编程-JOL分析对象头和性能分析_第2张图片
image.png

三、偏向锁对象头

这种情况下,加锁的过程中是轻量锁。

package com.layout;
import org.openjdk.jol.info.ClassLayout;

import static java.lang.System.out;
public class JOLBiasLock {
    static A a;
    public static void main(String[] args) throws Exception {
//        Thread.sleep(5000);
        a= new A();
        out.println("befor lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());
        synchronized (a){
            out.println("lock ing");
             out.println(ClassLayout.parseInstance(a).toPrintable());
        }
        out.println("after lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}

befor lock
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
com.layout.A 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)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

lock ing
com.layout.A object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           98 19 04 0f (10011000 00011001 00000100 00001111) (251926936)
      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     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

after lock
com.layout.A 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)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

lock ing 10011000是轻量级锁
在main方法中第一行加入Thread.sleep(5000);
lock ing 会是偏向锁
JVM延迟偏向锁是因为:如果不延迟,一上来就是偏向锁,假设程序后续还有线程调用,他会升级。jvm确定同步块中大部分代码都不是偏向锁,所以在启动的时候延迟。

四、偏向锁与轻量锁性能对比

A.java

package com.layout;

public class A {
    int i=0;
    // boolean flag =false;
    public synchronized void parse(){
        i++;
    }
}

package com.layout;
public class BiasAndLightPerformance {
    public static void main(String[] args) throws InterruptedException {
//        Thread.sleep(5000); //打开就是偏向锁,不打开就是轻量级锁
        A a = new A();
        long start = System.currentTimeMillis();
        //调用同步方法1000000000L 来计算1000000000L的++,对比偏向锁和轻量级锁的性能
        //如果不出意外,结果灰常明显
        for(int i =0;i<1000000000L;i++){
            a.parse();
        }
        long end = System.currentTimeMillis();
        System.out.println(String.format("%sms", end - start));
    }

    
}

轻量级锁:16208ms
偏向锁:1768ms
重量级锁:
A.java

package com.layout;

public class A {
    int i=0;
    // boolean flag =false;
    public synchronized void parse(){
        i++;
        HeavyLock.countDownLatch.countDown();
    }

}

HeavyLock.java

package com.layout;

import java.util.concurrent.CountDownLatch;

public class HeavyLock {
    static CountDownLatch countDownLatch = new CountDownLatch(1000000000);

    public static void main(String[] args) throws InterruptedException {
        final A a = new A();
        long start = System.currentTimeMillis();

        for (int i =0;i<2;i++){
            new Thread(()->{
                while (countDownLatch.getCount()>0){
                    a.parse();
                }
            }).start();
        }
        countDownLatch.await();
        long end = System.currentTimeMillis();
        System.out.println(String.format("%sms",end-start));
    }
}

重量锁:50023ms

轻量锁 重量锁 偏向锁
16208ms 50023ms 1768ms

五、重量锁的对象头

package com.layout;
import org.openjdk.jol.info.ClassLayout;

import static java.lang.System.out;
public class HeavyLockHead {
    static A a;
    public static void main(String[] args) throws Exception {
        //Thread.sleep(5000);
        a = new A();
        out.println("befre lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());//无锁

        Thread t1= new Thread(){
            public void run() {
                synchronized (a){
                    try {
                        Thread.sleep(5000);
                        System.out.println("t1 release");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t1.start();
        Thread.sleep(1000);
        out.println("t1 lock ing");
        out.println(ClassLayout.parseInstance(a).toPrintable());//轻量锁
        //此时t1线程把a锁住,并未释放。但是sync主线程这个时候过来竞争啊这把锁。所以锁会升级为重量锁
        sync();
        out.println("after lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());//重量锁

        System.gc();
        out.println("after gc()");
        out.println(ClassLayout.parseInstance(a).toPrintable());/无锁---gc
    }

    public  static  void sync() throws InterruptedException {
        synchronized (a){
            System.out.println("t1 main lock");
            out.println(ClassLayout.parseInstance(a).toPrintable());//重量锁
        }
    }
}

befre lock
# WARNING: Unable to attach Serviceability Agent. You can try again with escalated privileges. Two options: a) use -Djol.tryWithSudo=true to try with sudo; b) echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
com.layout.A 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)                           9f c1 00 f8 (10011111 11000001 00000000 11111000) (-134168161)
     12     4    int A.i                                       0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

t1 lock ing
com.layout.A object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           b0 39 42 02 (10110000 00111001 01000010 00000010) (37894576)
      4     4        (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
      8     4        (object header)                           9f c1 00 f8 (10011111 11000001 00000000 11111000) (-134168161)
     12     4    int A.i                                       0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

t1 release
t1 main lock
com.layout.A object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           4a ad 00 e2 (01001010 10101101 00000000 11100010) (-503272118)
      4     4        (object header)                           cd 7f 00 00 (11001101 01111111 00000000 00000000) (32717)
      8     4        (object header)                           9f c1 00 f8 (10011111 11000001 00000000 11111000) (-134168161)
     12     4    int A.i                                       0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

after lock
com.layout.A object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           4a ad 00 e2 (01001010 10101101 00000000 11100010) (-503272118)
      4     4        (object header)                           cd 7f 00 00 (11001101 01111111 00000000 00000000) (32717)
      8     4        (object header)                           9f c1 00 f8 (10011111 11000001 00000000 11111000) (-134168161)
     12     4    int A.i                                       0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

after gc()
com.layout.A object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
 																				  1是gc标识
      0     4        (object header)                           09 00 00 00 (0000  1     001 00000000 00000000 00000000) (9)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           9f c1 00 f8 (10011111 11000001 00000000 11111000) (-134168161)
     12     4    int A.i                                       0
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

六、如果调用wait方法则立即变为重量锁

public class JOLExample11 {
    static A a;
    public static void main(String[] args) throws Exception {
        //Thread.sleep(5000);
        a = new A();
        out.println("befre lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());

        Thread t1= new Thread(){
            public void run() {
                synchronized (a){
                    try {
                        synchronized (a) {
                            System.out.println("before wait");
                            out.println(ClassLayout.parseInstance(a).toPrintable());
                            a.wait();
                            System.out.println(" after wait");
                            out.println(ClassLayout.parseInstance(a).toPrintable());
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        t1.start();
        Thread.sleep(7000);
        synchronized (a) {
            a.notifyAll();
        }
    }
}

七、如果对象已经计算了hascode就不能偏向了

public class JOLExample8 {
   static A a;
    public static void main(String[] args) throws Exception {
        Thread.sleep(5000);
        a= new A();
        a.hashCode();
        out.println("befor lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());
        synchronized (a){
            out.println("lock ing");
            out.println(ClassLayout.parseInstance(a).toPrintable());
        }
        out.println("after lock");
        out.println(ClassLayout.parseInstance(a).toPrintable());
    }
}

你可能感兴趣的:(Java)