JVM创建对象的步骤的话题,在技术面试中经常被提到。不仅可以帮助我们更深入的理解JAVA虚拟机的工作原理,还能在面试中秀出我们的技术功底。
1.类加载检查
我们在代码中使用到某个类时,JVM需要先检查该类是否已经加载内存中,如果没有,JVM会通过类加载器去加载这个类,这个过程称为类加载检查,类检查的主要任务是确保所需的内在内存中可用,这是程序正常运行的前提。
类加载检查还包括对内的合法性进行检查,比如检查类的魔术、版本号等信息,以确保类文件的完整性和正确性,此外类检查还会检查类是否已经被加载过,以避免重复加载提高运行效率。分配内存一旦类加载检查通过,JVM需要在堆内存中对对象分配内存空间,这个过程需要考虑到对象的大小以及堆内存的可用空间。
2.内存分配
在进行内存分配时,JVM会根据对象的大小来决定在堆内存中分配多少空间,如果对象比较小,JVM会选择使用快速分配策略。
例如指针碰撞或者空闲列表,指针碰撞是一种简单的列存分配方式,他将对堆内存一分为二,一边用于以分配对象,另一边用于未分配对象,通过移动指针来实现内存分配,而空闲列表则将对堆内存划分为一系列大小不等的内存块,通过为护一个空隙列表记录可用的内存块,当需要分配内存时,从空闲列表中选择和小的内存块进行分配。
除了考虑对象大小外,JVM还需要考虑堆内存的可用空间,如果堆内存的可用空间不足以容纳对象,就会触发垃圾回收机器来释放一些无用的对象,已腾出足够的空间来分配新对象。
垃圾回收的具体策略和算法在不同的JVM实现中可能会有所不同,但其核心目标都是为了确保对堆内存的可用空间。
3.初始化零值
初始化零值,在内存分配完成后JVM会对对象的内存空间进行初始化,对于基本数据类型JVM会将其初始化为零值。例如,整形初始化为0,浮点型会被初始化为0.0,布尔型会被初始化为false,引用类型会被初始化为null,这样做的目的是为了确保对象的属性在使用之前都有一个明确的初始值,避免了因为未初始化而导致个程序错误。
在初始化零值的过程中,JVM会根据对象的类型和属性来逐个初始化对象的各个属性值,如果属性基本类型初始值是对应数据类型的零值,如果属性是引用类型,那么它的初始值null,通过这样的初始化过程,我们可以确保对象的各个属性都处于一个可控的状态,为后续的操作打下了良好的基础。
4.设置对象头
设置对象头,在内存分配和初始化零值完成后,JVM会在内存中为对象设置对象头,对象头是对象在内存中的标识符,包含一些必要的信息,例如对象的类型信息、GC相关信息等。
首先对象头会包含对象的类型信息,这个信息是类加载的时候确定的,它指示了对象所属的那个类型。这样JVM在操作对象的时候,可以根据对象中的类型信息来准确的调用对象的方法和属性,其次对象头还包含了GC相关的信息,比如对象的引用计数、对象的分代信息等,这些信息对于JVM的垃圾回收机制非常重要,他们能够帮助JVM正确的管理内存,及时回收使用的对象,避免内存泄露内存的问题。
除此之外,对象头还可能包含一些额外的信息,比如对象的哈希码、锁状态等。这些信息虽然不是必须的,但他们可以为对象提供额外的功能和特性,例如在多线程环境下,锁状态信息可以帮助JVM实现线程同步。
5.执行init方法
最后一步是执行对象的init方法。在JAVA中每个类都有一个与对应的构造方法,在对象创建的时候,JVM会调用该构造方法来初始化对象,这个过程就是执行init方法。
init方法主要作用是完成对象的初始化工作,包括对对象的属性进行赋值赋值、调用其他方法进行一些初始化操作等。在执行init方法之前JVM会为对象分配内存,初始化零值,设置对象头等操作,确保对象处于一个合法且可用的状态。在执行init方法的过程中,我们可以在构造方法中编写一些初始化逻辑,比如对对象的属性进行初始化,调用其他方法进行初始化操作等,这样当我们使用关键字创建对象的时候JVM就会按照我们定义的初始化逻辑来初始化对象,确保对象在创建之后处于一个正确的状态。
通过以上五个步骤,JVM成功创建了一个对象,当我们使用new关键字,创建一个对象的时候,其实就是在触发了JVM的这个创建对象的过程。了解这个过程不仅可以帮助我们更好的理解JAVA程序的执行流程,还能够在技术面试中体现我们的技术功底。希望通过今天的分享,大家对于JVM创建过程有了更深入的了解。