JVM 创建 Java 对象的流程:类的加载,内存分配、对对象进行必要的设置、执行 <init> 方法初始化。
1. JVM 创建 Java 对象
使用 new 关键字可以创建一个类的对象。
new 指令在虚拟机中的执行操作:
- 类的加载:首先在常量池(方法区中)去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,则需要进行类的加载。
- 内存分配:类加载通过之后,虚拟机会给新生对象分配内存, 对象所需内存大小在加载之后便可以确定,分配内存即是在 Java 堆中划分出来。
假设 Java 堆中的内存是绝对规整(不同的垃圾回收算法,堆中的内存是不一样的),所有的空闲内存放在一边,被使用的内存放在一边,中间放着一个指针作为分界点,分配内存的则会将指针向被使用的内存移动。如果Java 堆中的内存不是规整的,则需要维护一个列表,记录那些内存是空闲的。
内存分配的并发问题 :Java中的对象创建是相当频繁,简单的指针移动会出现问题,解决方法如下所示。
(1)方法一:JVM虚拟机使用 CAS + 失败重试 的方法保证原子性。
(2)方法二:把内存分配按照线程划分在不同区域,即每个线程先分配一小块内存,称为本地线程分配缓冲TLAB,那个线程需要分配内存,就在那个TLAB上分配,只有TLAB用完并分配新的TLAB时才需要同步锁定。
内存分配完成后,虚拟机需要将分配的内存空间全部初始为0,不包括对象头。
- 虚拟机需要对对象进行必要的设置 , 如 :设置 这个对象是哪个类的实例,如何找到类的元数据,对象的hash码、对象的 GC 分代年龄 , 这些信息存储在对象头中。根据虚拟机当前的运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置模式。
- 执行 <init> 方法进行初始化,把对象按照程序员的意愿初始化。
至此这个对象已经产生,可以被调用了。
参考文献
- 深入理解Java虚拟机:JVM高级特性与最佳实践 / 周志明著. —— 2 版 . —— 北京:机械工业出版社,2013.6 (2019.1重印)