• 类加载检查
    Java虚拟机(jvm)在读取一条new指令时候,首先检查能否在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否被加载、解析和初始化。如果没有,则会先执行相应的类加载过程。
+  类加载机制(加载、验证、准备、解析和初始化)
       + java虚拟机将编译后的class文件加载到内存中,进行校验、转换、解析和初始化,到最终的使用。这就是java类加载机制;
    1、加载

      在加载阶段,虚拟机主要执行以下三个操作

      1)、通过类的全限定名来获取定义这个类的二进制字节流。

      2)、将这个字节流所代表的静态存储结构转化成方法区的运行时数据结构。

      3)、在内存中生成一个代表这个类的Class对象,作为方法区这个类的各种数据的访问入口。

     这个阶段相比其他阶段来说,是开发人员可控性最强的阶段。因为这个阶段既能使用系统提供的加载器(这个加载器后面会进行介绍)加载,又能通过开发人员自定义的加载器进行加载。

     在加载这个阶段还有一个需要注意的地方,在执行第一个操作时,需要知道可以从哪里获取class文件,例如:

      1)、从压缩文件中读取(JAR,WAR等)

      2)、从本地磁盘中获取

      3)、从网络上获取(Applet)

      4)、运行过程中动态生成(动态代理)

      5)、其他文件生成(jsp生成对应的class文件)

      6)、从数据库中读取

  2、验证

      验证阶段主要有4个阶段的验证:文件格式验证、元数据验证、字节码验证和符号验证

      2.1、文件格式验证

  这一阶段要验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理,主要包括魔数、版本号、常量池等验证。

      2.2、元数据验证

  这个阶段是对字节码描述的信息进行语义分析,以保证其描述的信息符合java语言规范的要求。主要包括是否有父类,类中的字段、方法是否与父类冲突,如果不是抽象类,是否实现了其父类或接口中要求实现的所有方法等;

      2.3、字节码验证

  这个阶段是在元数据验证之后,对类的方法体进行校验分析,保证被校验类的方法在运行时不会做出危害虚拟机的安全事件,主要目的是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。也是验证过程最复杂的一个阶段。

      2.4、符号引用验证

   这个阶段的校验发生在虚拟机将符号引用转化为直接引用的时候。是对类自身以外的信息进行匹配性校验。主要目的是确保解析动作能正常执行。

  3、准备

   准备阶段是为类变量分配内存并设置类变量初始值的阶段,分配这些内存是在方法区里面进行的,这个阶段有两点需要重点介绍:

   1)、只有类变量(被static修饰的变量)会分配内存,不包括实例变量,实例变量是在对象实例化的时候在堆中分配内存的。

   2)、设置类变量的初始值是数量类型对应的默认值,而不是代码中设置的默认值。例如public static int number=111,这类变量number在准备阶段之后的初始值是0而不是111。而给number赋值为111是在初始化阶段。

 4、解析

   解析阶段是虚拟机将常量池里内的符号引用转换为直接引用。这里注意2个概念:

   1)、符号引用:以一组符号来描述所有引用的目标,符号可以是任何形式的字面量,只要使用时能正确定义到目标即可。

   2)、直接引用:可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。

  解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符等7类符号引用进行的。

 5、初始化

   这个阶段是类加载过程的最后一步,是代码真正开始执行的时候,在这个阶段,开发人员可以根据自己的需求去给类变量初始化赋值。简单来说就是执行类构造器()方法的过程。

+ 内存分配
在通过(1)后,则开始为新生的对象分配内存。该对象所需的内存大小在类加载完成后便可确定,因此为每个对象分配的内存大小是确定的。而分配方式主要有两种,分别为:

1、指针碰撞

  应用场合:堆内存规整(通俗的说就是用过的内存被整齐充分的利用,用过的内存放在一边,没有用过的放在另外一边,而中间利用一个分界值指针对这两边的内存进行分界,从而掌握内存分配情况)。即在开辟内存空间时候,将分界值指针往没用过的内存方向移动向应大小位置即可)。将堆内存这样划分的代表的GC收集器算法有:Serial,ParNew
        2、空闲列表
  应用场合;堆内存不规整(虚拟机维护一个可以记录内存块是否可以用的列表来了解内存分配情况)即在开辟内存空间时候,找到一块足够大的内存块分配给该对象即可,同时更新记录列表。将堆内存这样划分的代表的GC收集器算法有:CMS
  • 初始化默认值
    第(2)步完成后,紧接着,虚拟机需要将分配到的内存空间都进行初始化(即给一些默认值),这将做是为了保证对象实例的字段在Java代码中可以在不赋初值的情况下使用。程序可以访问到这些字段对用数据类型的默认值。
  • 设置对象头
    初始化(3)完成后,虚拟机对对象进行一些简单设置,如标记该对象是那个类的实例,这个对象的hash码,该对象所处的年龄段等等(这些可以理解为对象实例的基本信息)。这些信息被卸载对象头中。jvm根据当前的运行状态,会给出不同的设置方式。
  • 执行初始化方法
    在(4)完成后,最后执行由开发人员编写的对象的初始化方法,把对象按照开发人员的设计进行初始化,一个对象便创建出来了。