【JVM】详细解析java创建对象的具体流程

这篇具有很好参考价值的文章主要介绍了【JVM】详细解析java创建对象的具体流程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、java创建对象的几种方式

1.1、使用new关键字

 1.2、反射创建对象

1.2.1、Class.newInstance创建对象

1.2.2、调用构造器再去创建对象Constructor.newInstance

 1.3、clone实现

1.4、反序列化

二、创建对象的过程

2.1、分配空间的方式

1、指针碰撞

2、空闲列表

3、怎么选择分配方式

三、注意事项


一、java创建对象的几种方式

1.1、使用new关键字

调用类的构造方法创建对象

【JVM】详细解析java创建对象的具体流程,jvm,java,开发语言

 1.2、反射创建对象

1.2.1、Class.newInstance创建对象

【JVM】详细解析java创建对象的具体流程,jvm,java,开发语言

1.2.2、调用构造器再去创建对象Constructor.newInstance

先通过反射获取类中无参构造器,然后通过newInstance()获取对象

【JVM】详细解析java创建对象的具体流程,jvm,java,开发语言

 1.3、clone实现

通过Clone创建对象,首先实体类中必须先实现Cloneable接口并复写Object的clone方法(因为Object的这个方法是protected的)

【JVM】详细解析java创建对象的具体流程,jvm,java,开发语言

 【JVM】详细解析java创建对象的具体流程,jvm,java,开发语言

1.4、反序列化

序列化:指把 Java 对象转换为字节序列的过程;
反序列化:指把字节序列恢复为 Java 对象的过程;
此方式需要类先实现Serializable接口

【JVM】详细解析java创建对象的具体流程,jvm,java,开发语言

public class TestStack {
    public static void main(String[] args) throws Exception {
        File file =new File("M:/Serializable.txt");
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
        UserParam userParam =new UserParam("hello");
        outputStream.writeObject(userParam);
        FileInputStream fileInputStream  = new FileInputStream(file);
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        UserParam userParam1 = (UserParam)objectInputStream.readObject();
        userParam1.setNickName("world");
        System.out.println(userParam1);
    }
}

二、创建对象的过程

当Java虚拟机遇到一条字节码new指令时:

1、检查类是否已经被加载

        去常量池中查找该引用所指向的类有没有被虚拟机加载,如果没有被加载,那么会进行类的加载过程。类的加载过程需要经历:加载、链接、初始化三个阶段。对象的大小,在类加载完成时确定。(jdk1.8中,运行时常量池、类常量池存在于方法区中。)

2、 为对象分配内存空间

        JVM为对象分配空间,即把一块确定大小的内存块从Java堆中划分出来。

2.1、分配空间的方式

1、指针碰撞

        假设Java堆中内存是绝对规整的,所有被使用过的内存都被放在一边,空闲的内存被放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间方向挪动一段与对象大小相等的距离。

①正常情况

【JVM】详细解析java创建对象的具体流程,jvm,java,开发语言

②给对象分配内存后

【JVM】详细解析java创建对象的具体流程,jvm,java,开发语言

 

这种方式的优点是工作简单,效率高,只需要移动指针就可以分配内存空间。

缺点也很明显:由于用指针碰撞分配内存空间分为两步:

1、读取指针当前的位置。

2、根据自身大小移动指针,不是原子操作,对象创建在虚拟机中是非常频繁的操作,在并发情况下,会导致执行读操作或执行写操作的结果与预设的结果不一致(指针划分不一致)。

        例如:线程A要给对象分配8kb,读取到指针当前的位置,时间片用完,切换到线程B,线程B要给它的对象分配16kb,也读取到指针当前的位置(和线程A读取到的一样),将指针向空闲内存方向移动16kb大小,线程B时间片用完,切换到线程A继续执行,由于线程A使用的指针位置还是之前读到的。(线程不安全问题)

③针对指针碰撞线程不安全,有两种方案:

1、同步处理(加锁)分配内存空间行为

采用 CAS 分配重试的方式来保证更新操作的原子性

2、把内存分配行为按照线程,划分在不同的内存空间进行

1、即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB),哪个线程要分配内存,就在哪个线程的本地缓冲区中分配,只有本地缓冲区用完了,分配新的缓存区时才需要同步锁定
2、虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。

2、空闲列表

        如果Java堆中的内存并不是规整的, 已被使用的内存和空闲的内存相互交错在一起,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录。

3、怎么选择分配方式

        两种方式的选择由 Java 堆是否规整决定,Java 堆是否规整是由选择的垃圾收集器是否具有压缩整理能力决定的。

①将内存空间初始化为零值
        内存分配完成之后,虚拟机必须将分配到的内存空间(但不包括对象头)都初始化为零值。零值初始化意思就是对对象的字段赋0值,或者null值,这也就解释了为什么这些字段在不需要进程初始化时候就能直接使用。
        如果使用了TLAB的话,这一项工作也可以提前至TLAB分配时顺便进行。

②对对象进行必要的设置
        例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头中。

        从虚拟机的视角来看,一个新的对象已经产生了。但是从Java程序的视角看来,对象创建才刚刚开始——构造函数,即Class文件中的()方法还没有执行,所有的字段都为默认的零值,对象需要的其他资源和状态信息也还没有按照预定的意图构造好。

③执行实例的初始化方法init

        init方法包含成员变量、构造代码块的初始化,按照声明的顺序执行,执行对象的构造
方法,并把堆内对象的首地址赋值给引用变量。至此,对象创建成功。

【JVM】详细解析java创建对象的具体流程,jvm,java,开发语言

三、注意事项

        并发情况下,需要考虑操作的步骤是不是原子性,如果不是,就要加锁。原子性就是动作不能再继续被拆分了,读是原子性,写也是原子性,但是读加上写就不是原子性。文章来源地址https://www.toymoban.com/news/detail-614044.html

到了这里,关于【JVM】详细解析java创建对象的具体流程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java进阶(1)——JVM的内存分配 & 反射Class类的类对象 & 创建对象的几种方式 & 类加载(何时进入内存JVM)& 注解 & 反射+注解的案例

    1.java运行时的内存分配,创建对象时内存分配; 2.类加载的顺序,创建一个唯一的类的类对象; 3.创建对象的方式,new,Class.forName,clone; 4.什么时候加载.class文件进入JVM内存中,看到new,Class.forName; 5.如何加载?双亲委托(委派)机制:安全;AppClassLoader; 6.反射实质:能

    2024年02月14日
    浏览(41)
  • Jvm创建对象之内存分配-JVM(七)

    上篇文章介绍了jvm创建,会校验是否已加载类,没有则加载,通过之前学的源码,classLoader加载完之后,虚拟机开始给类分配内存,指针移动分配和free链表分配,解决并发分配情况用cap和TLAB方法。之后设置对象头部信息,有mark word线程锁,分代年龄等,klass pointer。还有指针

    2024年02月13日
    浏览(67)
  • JVM中对象创建过程

    在JVM中对象的创建,我们从一个new指令开始: 这个过程大概图示如下: 虚拟机收到new指令触发。 类加载检查:如果类没有被类加载器加载,则执行类加载流程(将class信息加载到JVM的运行时数据区的过程),对象所需内存大小在类加载完后可以完全确定。 对象分配内存:从

    2024年03月22日
    浏览(45)
  • 04-JVM对象创建深度剖析

    上一篇:03-JVM内存模型剖析与优化 对象创建的主要流程: 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。 ne

    2024年02月09日
    浏览(36)
  • jvm对象创建和内存分配优化

    1、类加载检测 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。 new指令对应语言层面讲是,new、对

    2024年02月13日
    浏览(56)
  • JVM面试题-JVM对象的创建过程、内存分配、内存布局、访问定位等问题详解

    内存分配的两种方式 指针碰撞 适用场合:堆内存 规整 (即没有内存碎片)的情况下。 原理:用过的内存全部整合到一边,没有用过的内存放在另一边,中间有一个分界指针,只需要向着没用过的内存方向将该指针移动对象内存大小位置即可。 使用该分配方式的GC收集器:

    2024年02月08日
    浏览(49)
  • JVM对象创建与内存分配机制深度剖析

    (1)类加载检查 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程; 所以所类加载是 懒加载 ; new指令对应到语

    2024年02月13日
    浏览(47)
  • JVM运行时区域——对象创建内存分配过程

            新创建的对象 , 都存放在伊甸园区域 ,当垃圾回收时,将伊甸园区域的垃圾数据销毁,然后将存活的对象转移到幸存者0区域,之后创建的新的对象还是存放在伊甸园区域,等到再次垃圾回收后,将伊甸园区域和幸存者0区域中存活的对象一起转移到幸存者1区域中

    2024年02月15日
    浏览(46)
  • Java进阶(4)——结合类加载JVM的过程理解创建对象的几种方式:new,反射Class,克隆clone(拷贝),序列化反序列化

    1.类什么时候被加载到JVM中,new,Class.forName: Class.forName(“包名.类名”); 2.创建对象的方式,反射,本质是获得类的类对象Class; 3.克隆clone,深拷贝,浅拷贝的对比; 4.序列化和反序列化的方式; Hello h; // 此时没有用Hello,jvm并没有进行类加载 看到new : new Book() Class.forName:

    2024年02月12日
    浏览(42)
  • JVM 创建对象时分配内存的几种方法、分配方法的选择

            假设Java堆中内存是绝对规整的,所有被使用过的内存都被放在一边,空闲的内存被放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那 个指针向空闲空间方向挪动一段与对象大小相等的距离。         如果Java堆中的内存并不是规

    2024年02月10日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包