JVM(三)jvm中对象的创建的过程

在JVM中创建的对象示例放在堆中,那么当JVM执行new语句时,具体是如何操作的呢?

(1)首先在方法区的常量池中查看是否有new 后面参数(也就是类名)的符号引用,并检查是否有类的加载信息也就是是否被加载解析和初始化过。如果已经加载过了就不在加载,否则执行类的加载全过程

(2)加载完类后,JVM开始为这个新生对象分配内存,这个时候选用的分配内存的方法取决于堆内存是否是规整的

         注意:这种情况需要考虑对象在虚拟机的创建中是否是频繁的,因为在多线程的情况下是不安全的,比如对象A正在使用一个指针位置划分内存区域,指针还没来得及修改,对象B也开始划分内存,那就是使用原来的指针位置,就会发生问题

      解决办法:一、对分配内存的方法加同步锁;

                        二、把分配内存的动作按照不同的线程分配在不同的空间中运行,即为每个线程分配一小块内存,叫做本地线程分                                   配缓存,(TLAB).那么每个线程的分配内存空间就在各自的TLAB中进行。(就是把堆中未分配的内存再分配                                 给不同的线程)

  • 如果JVM的垃圾回收器带Compact功能,也就是压缩整理内存,那么内存就是规整的,也就是已经分配的内存放在一起,未分配的内存放在一起,中间用指针间隔,这样新分配内存只需要移动指针,这种方法叫做“指针碰撞”
  • 那么如果JVM的垃圾回收器采用的算法没有Compact功能,对应的堆内存就不是规整的,也就是未分配的内存不连续,那么JVM就需要维护一个列表记录哪些内存区域是可以分配的,这种方法叫做“空闲列表”

(3)对象的内存分配好之后,JVM会把对象的内存空间都初始化为零值(不包括对象头,一个对象在内存中的存储包括三个部分:对象头,实例数据,对其填充,后面再做详细解释)。这一步操作保证对象在java中没有赋值就可以使用,比如  Integer  i=new Integer();创建完对象i,i的初始值是0;而不是null;

(4)接下来JVM就会对该新生对象的进行设置,填写对象头的内容。对象头中有对象自身的运行时数据,包括对象的hash码,GC分代年龄信息和类型指针(通过这个指针JVM才能知道这个对象是哪个例的实例)。根据虚拟机现在是否使用偏向锁会有不同的设置


 上面的过程全部执行完,在JVM一个对象已经产生。在java中<init>方法还没有执行,也就是还没有调用类的构造器,所以字段还是零值,也就是在java中还没有初始化,执行完new以后,JVM会根据字节码中是否有(invokespecial指令)决定是否执行完new就开始执行<init>,执行完一个对象就真正产生了

区别init()方法和cinit()方法

clinit方法

在加载类的时候调用,加载类的过程:类加载—–验证—-解析—–初始化,JVM会在初始化阶段调用clinit方法来收集类中的类变量的赋值动作和静态语句块(static{}块)中的语句等

init()方法

是对象构造器方法,也就是说在程序执行 new 一个对象调用该对象类的 constructor 方法时才会执行init方法

猜你喜欢

转载自blog.csdn.net/wangdongli_1993/article/details/81152273