在java中,对象的创建仅仅只是new一下而已,但是其实远远没有这么简单.

一. 检查是否类是否加载

当java虚拟机遇到一条new指令对应的字节码时候,首先将会去检查这个指令的参数能否在常量池中,获取到一个类的符号引用.并且检查这个符号引用代表的类是否被加载,解析和初始化过.如果没有,那么就先执行类的加载过程.

二. 分配内存

对象所需要的内存大小,在类加载之后就可以确定.所以就是从java堆内存中划分一块确定的内存出来.

如何分出来有两种方法.

1. 指针碰撞

假设堆内存中是规整连续的,使用过和没使用过的严格分开,这样只需要维护一个指针,分配内存之后,移动一下指针就可以了

JVM对象创建过程

2. 空闲列表

如果java堆内存并不规整,已使用和未占用杂乱放置,就无法使用简单碰撞

如下图所示,实际要复杂的多,不同区块的大小也不一样,当有新的对象需要分配内存时候,就从空闲列表中取出一块足够大的内存分配给它(能力有限,怎么简单怎么画了)

JVM对象创建过程

内存分配总结

一般带有压缩整理功能的(ParNew),可以使用指针碰撞方法分配内存,基于标记-清除算法的(CMS),一般使用空闲列表

HotSpot虚拟机有一些改进,在cms回收器的实现下,会先使用空闲列表,先拿到一些大块的内存,在这些大块的内存里面,又可以使用指针碰撞方法

如果只按照上面的分配内存的办法,是会产生线程安全问题,所以实际上,在分配内存的时候,还会加入cas失败重试的机制

三. 将对象的属性初始化为零值

四. 设置对象头信息

对象头包括两类信息

  1. 存储对象自身的运行时数据

    如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等

  2. 类型指针

    即对象指向它的类型元数据的指针,Java虚拟机通过这个指针来确定该对象是哪个类的实例

  3. 如果是数组,还要包括数组的长度信息

五. 执行init方法,也就是java的构造函数

其实上面四步执行完,虚拟机的对象创建已经完成,后面的init方法即java中的构造函数,就是程序员按照自己意愿对此对象进行的初始化

相关文章:

  • 2021-08-23
  • 2021-11-20
  • 2021-10-26
  • 2022-02-12
  • 2022-01-19
  • 2021-08-15
猜你喜欢
  • 2021-04-09
  • 2021-06-12
  • 2021-05-05
  • 2021-11-01
  • 2021-06-08
  • 2021-07-31
相关资源
相似解决方案