java中创建对象的三种方式为:
1》clone()
2》反序列化
3》使用new关键字进行创建对象。
创建过程如下所示:
1.虚拟机遇到一条new指令的时候,首先将检查这个指令的参数是否在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否被加载,解析和初始化过 。虚拟机会深入到class的层次。
如果没有,那么就必须要先执行相应的类加载过程。
在类加载检查通过后,虚拟机为新生对象分配内存,对象所需要的内存在类加载完成之后就可以完全确定了。
为对象分配内存也就是从堆中划分出来一块内存,根据内存分配的结果定义可以得知,指针应该是有一张表进行维护的,已经用了的指针,以及还未进行引用到指针。否则内部就会发生很大的变化,从而导致内存的分配发生紊乱。
除了分配内存之外,有些事情也是我们需要去考虑的,
第一。对象在虚拟机中内存的创建是十分的频繁的,即使是在仅仅修改一个指针所指向的位置,在并发的情况下并不是线程安全的,因为在实际情况中,线程的是在单位时间进行切换的。
可能出现的情况如下所示:
正在给A分配内存,指针还没来得及修改,给A分配内存,对象B使用了准备给A的那个内存指针来进行内存分配的情况。
解决这种问题的方式是对分配内存的动作进行同步处理
虚拟机本质上是采用CAS配上失败重试的方式保证更新操作的原子性,可以理解为在指针进行分配内存的过程中引用是原子性的。
另一种是把内存分配的动作按照线程划分为不同的空间之中进行,即每个线程在Java堆中,预先分配一个内存。
称之为本地线程分配缓冲,类似于增加了一个类似于指针分配列表的东西。
称为TLAB,可以理解为线程池中的队列,那个线程要分配内存,就在那个线程的TLAB上面进行分配,只有TLAB全部用完之后,并重新分配TLAB的时候,才需要进行同步锁定,虚拟机是是否使用TLAB
可以通过-XX:+/-UseTLAB来进行设定。
内存分配完成之后,虚拟机需要将分配到的内存空间都初始化为零值,也即是TLAB在引用内存的时候,这一工作过程可以在TLAB分配之前进行,这是一个保护机制,这一步操作是保证了对象的实例字段在java代码中可以不赋初值就进行直接使用,程序能访问到这些字段的数据类型所对应的零值。
栈是管对象的。是引用,用到了栈帧,总结一下。
虚拟机对对象进行必要的设置,例如这个对象是那个类的实例,如何才能找到类的元数据信息,对象的hash码,根据虚拟机的当前运行状态的不同,如是否启用偏向锁,
其头部会有不同的设置方式,关于对象头的具体内容,稍后再做详细的介绍。
从虚拟机的视角来看,一个新的对象已经产生了,但是从java程序的视角来看,对象建立才刚刚开始---------《init》方法还没有执行,所有的字段都还为0
执行顺序如下所示:
执行完new指令之后,会接着执行<init>方法,把对象按照程序员的意愿进行初始化的操作,也就是使用不同的初始化方法进行操作。这样一个真正可用的对象才算完全出来了。