美文网首页
走进JVM-对象实例化

走进JVM-对象实例化

作者: 奋斗_登 | 来源:发表于2023-11-06 16:12 被阅读0次

      Java 是面向对象的静态强类型语言,声明并创建对象的代码很常见,根据某个类声明一个引用变量指向被创建的对象,并使用此引用变量操作该对象。在实例化对象的过程中,JVM 中发生了什么化学反应呢?

    1.下面从最简单的 Object ref= new Object();代码进行分析,利用javap -verbose -p 命令查看对象创建的字节码如下:
          stack=2, locals=2, args_size=1
             0: new           #2                  // class java/lang/Object
             3: dup
             4: invokespecial #1                  // Method java/lang/Object."<init>":()V
             7: astore_1
             8: return
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0       9     0  args   [Ljava/lang/String;
                8       1     1   ref   Ljava/lang/Object;
    
    • NEW: 如果找不到Class对象,则进行类加载。加载成功后,则在堆中分配内存,从 Object 开始到本类路径上的所有属性值都要分配内存。分配完毕之后,进行零值初始化。在分配过程中,注意引用是占据存储空间的,它是一个变量,占用4个字节。这个指令完毕后,将指向实例对象的引用变量压入虚拟机栈顶。
    • DUP:在栈顶复制该引用变量,这时的栈顶有两个指向堆内实例对象的引用变量。如果 <init> 方法有参数,还需要把参数压入操作栈中。两个引用变量的目的不同,其中压至底下的引用用于赋值,或者保存到局部变量表,另个栈顶的引用变量作为句柄调用相关方法。
    • INVOKESPECIAL: 调用对象实例方法,通过栈顶的引用变量调用<init>方法。<clinit> 是类初始化时执行的方法,而 <init> 是对象初始化时执行的方法。
    2.前面所述是从字节码的角度看待对象的创建过程,现在从执行步骤的角来分析。
    • 确认类元信息是否存在。当JVM 接收到 new 指令时,首先在 metaspace内查需要创建的类元信息是否存在。若不存在,那么在双亲委派模式下,使用当前类加载器以ClassLoader+ 包名+类名为 Key进行查找对应的class文件如果没有找到文件,则抛出 ClassNotFoundException 异常;如果找到,则讲行类加载,并生成对应的Class 类对象。
    • 分配对象内存。首先计算对象占用空间大小,如果实例成员变量是引用变量,仅分配引用变量空间即可,即 4 个字节大小,接着在堆中划分一块内有给新对象。在分配内存空间时,需要进行同步操作,比如采用CAS( Compar And Swap)失败重试、区域加锁等方式保证分配操作的原子性。
    • 设定默认值。成员变量值都需要设定为默认值,即各种不同形式的零值。
    • 设置对象头。设置新对象的哈希码、GC信息、锁信息、对象所属的类元信息等这个过程的具体设置方式取决于JVM实现。
    • 执行 init 方法。初始化成员变量,执行实例化代码块,调用类的构造方法并把堆内对象的首地址赋值给引用变量。

    相关文章

      网友评论

          本文标题:走进JVM-对象实例化

          本文链接:https://www.haomeiwen.com/subject/htztwdtx.html