zoukankan      html  css  js  c++  java
  • 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、执行引擎

    ---

    ----

  • 相关阅读:
    多线程的几种实现方法详解
    Java线程编程中isAlive()和join()的使用详解
    MyEclipse在不同编辑面间快速切换
    MyEclipse中设置代码块快捷键
    MyEclipse设置文件编码
    Oracle安装后遇到错误:The Network Adapter could not establish the connection
    Java中的Runtime类
    Java中接口的特点
    Java中三种常见的注释(注解) Annotation
    Java中的泛型
  • 原文地址:https://www.cnblogs.com/xy-ouyang/p/15357752.html
Copyright © 2011-2022 走看看