木心

毕竟几人真得鹿,不知终日梦为鱼

导航

JVM(四)

 

1、对象的实例化内存布局与访问定位

1.1、对象实例化的几种方式

1)new:最常见的方式,静态方法,xxxBuild/xxxFactory的静态方法
2)Class的newInstance():反射的方式,只能调用空参构造器,权限必须是public
3)Constructor的newInstance(xxx):反射的方式,可以调用空参、带参构造器,权限没有要求
4)clone:不调用任何构造器,当前类需要实现clonable接口,实现clone()
5)反序列化:从文件中或网络中获取一个对象的二进制流
6)第三方库Objenesis

 

1.2、字节码角度看对象的创建过程

public class Demo03 {
    
    public static void main(String[] args) {
        Object obj = new Object();
    }
    
}

  javap -v -p Demo03.class > Demo03.txt

Classfile /D:/workspaces/eclipse201812_workspace/demo/bin/com/oy/Demo03.class
  Last modified 2021-10-10; size 454 bytes
  MD5 checksum 74095293acc6e6bda439cfc9bb4a6aa6
  Compiled from "Demo03.java"
public class com.oy.Demo03
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // com/oy/Demo03
   #2 = Utf8               com/oy/Demo03
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/oy/Demo03;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               obj
  #19 = Utf8               Ljava/lang/Object;
  #20 = Utf8               MethodParameters
  #21 = Utf8               SourceFile
  #22 = Utf8               Demo03.java
{
  public com.oy.Demo03();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 10: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/oy/Demo03;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #3                  // class java/lang/Object
         3: dup
         4: invokespecial #8                  // Method java/lang/Object."<init>":()V
         7: astore_1
         8: return
      LineNumberTable:
        line 13: 0
        line 14: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;
            8       1     1   obj   Ljava/lang/Object;
    MethodParameters:
      Name                           Flags
      args
}
SourceFile: "Demo03.java"

 

1.3、对象创建的六个步骤

1)判断对象对应的类是否加载、链接、初始化
2)为对象分配内存,如果内存规整,指针碰撞;如果内存不规整,虚拟机需要维护一个空闲列表。
3)处理并发安全问题,采用CAS失败重试、区域加锁保证更新的原子性,每个线程预先分配一块TLAB,通过-XX:+/-UseTLAB参数来设定。
4)初始化分配到的空间,所有属性设置默认值,保证对象实例字段在不显示赋值时可以直接使用。
5)设置对象的对象头。
6)执行init方法进行初始化。在Java程序的视角看来,初始化才正式开始。初始化成员变量,执行实例化代码块,调用类的构造方法,并把堆内对象的首地址赋值给引用变量。因此一般来说(由字节码中是否跟随有invokespecial指令所决定),new指令之后会接着就是执行方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全创建出来。
public class Person {
    /*
     * 给对象属性赋
     * 1)属性的默认初始化 ==> 2)显示初始化  ==> 3)代码块中赋值  ==> 4)构造器中赋值
     */
    private int id = 111;
    
    {
        id = 222;
    }
    
    public Person() {
        id = 333;
    }
    
    {
        id = 444;
    }
    
    public static void main(String[] args) {
        Person p = new Person();
        System.out.println(p.id);
    }
}

  javap -v -p Person.class > Person.txt

Classfile /D:/workspaces/eclipse201812_workspace/demo/bin/com/oy/Person.class
  Last modified 2021-10-10; size 638 bytes
  MD5 checksum 6beef92d37323367617e3d8ea8aa9f6e
  Compiled from "Person.java"
public class com.oy.Person
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // com/oy/Person
   #2 = Utf8               com/oy/Person
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               id
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Methodref          #3.#11         // java/lang/Object."<init>":()V
  #11 = NameAndType        #7:#8          // "<init>":()V
  #12 = Fieldref           #1.#13         // com/oy/Person.id:I
  #13 = NameAndType        #5:#6          // id:I
  #14 = Utf8               LineNumberTable
  #15 = Utf8               LocalVariableTable
  #16 = Utf8               this
  #17 = Utf8               Lcom/oy/Person;
  #18 = Utf8               main
  #19 = Utf8               ([Ljava/lang/String;)V
  #20 = Methodref          #1.#11         // com/oy/Person."<init>":()V
  #21 = Fieldref           #22.#24        // java/lang/System.out:Ljava/io/PrintStream;
  #22 = Class              #23            // java/lang/System
  #23 = Utf8               java/lang/System
  #24 = NameAndType        #25:#26        // out:Ljava/io/PrintStream;
  #25 = Utf8               out
  #26 = Utf8               Ljava/io/PrintStream;
  #27 = Methodref          #28.#30        // java/io/PrintStream.println:(I)V
  #28 = Class              #29            // java/io/PrintStream
  #29 = Utf8               java/io/PrintStream
  #30 = NameAndType        #31:#32        // println:(I)V
  #31 = Utf8               println
  #32 = Utf8               (I)V
  #33 = Utf8               args
  #34 = Utf8               [Ljava/lang/String;
  #35 = Utf8               p
  #36 = Utf8               MethodParameters
  #37 = Utf8               SourceFile
  #38 = Utf8               Person.java
{
  private int id;
    descriptor: I
    flags: ACC_PRIVATE

  public com.oy.Person();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #10                 // Method java/lang/Object."<init>":()V
         4: aload_0
         5: bipush        111
         7: putfield      #12                 // Field id:I id字段显示初始化为111
        10: aload_0
        11: sipush        222
        14: putfield      #12                 // Field id:I  id字段代码块赋值222
        17: aload_0
        18: sipush        444
        21: putfield      #12                 // Field id:I  id字段代码块赋值444
        24: aload_0
        25: sipush        333
        28: putfield      #12                 // Field id:I  id字段构造器赋值333
        31: return
      LineNumberTable:
        line 17: 0
        line 11: 4
        line 14: 10
        line 22: 17
        line 18: 24
        line 19: 31
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      32     0  this   Lcom/oy/Person;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #1                  // class com/oy/Person
         3: dup
         4: invokespecial #20                 // Method "<init>":()V
         7: astore_1
         8: getstatic     #21                 // Field java/lang/System.out:Ljava/io/PrintStream;
        11: aload_1
        12: getfield      #12                 // Field id:I
        15: invokevirtual #27                 // Method java/io/PrintStream.println:(I)V
        18: return
      LineNumberTable:
        line 26: 0
        line 27: 8
        line 28: 18
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      19     0  args   [Ljava/lang/String;
            8      11     1     p   Lcom/oy/Person;
    MethodParameters:
      Name                           Flags
      args
}
SourceFile: "Person.java"

 

1.4、对象的内存布局

 

 

 

 

 

1.5、对象的访问定位

  JVM是如何通过栈帧中的对象引用访问到其内部的对象实例的呢?定位,通过栈上reference访问


  对象访问方式主要有两种:1)句柄访问  2)直接指针(HotSpot采用)。句柄访问好处:reference中存储稳定句柄地址,对象被移动(垃圾收集时移动对象很普遍)时只会改变句柄中实例数据指针即可,reference本身不需要被修改。

 

 

2、执行引擎

 

 

 

 

 

 

 

 

 

 

---

 

 

 

 

 

 

 

 

 

 

 

 

----

posted on 2021-09-30 17:46  wenbin_ouyang  阅读(33)  评论(0编辑  收藏  举报