原标题:3分钟 快速理解JVM创建对象的步骤!
我们平时创建一个对象只需要new。然而我们知道对象的创建到底经历了哪些呢?实际上只不过仅仅的3步就完成了。先来看看完整的创建过程,再来一步一步的分析。
| 是什么
要创建对象肯定首先要知道是什么、有没有。所以首先就是找到对象的类信息。从上一篇文章中我们知道类信息都是放到方法区的。
从这里看出类信息放到方法区是很有必要的,因为每个线程每个方法都可能需要这些信息。
| 放哪里
都知道对象是放到Java堆中的,同时对象是随时都在创建的,当多个线程运行的时候就有可能把对象放到同一个地方,那么肯定就会有线程拿到不是他想要的对象。
这里有两种解决方案:1、把分配内存空间这个操作给同步,虚拟机采用的CAS失败重试机制保证操作的原子性。2、先为每个现在分配一点内存,叫本地线程分配缓冲(Thread Local Allocation Buffer,TLAB),当用完的时候分配新的的时候在加同步操作。虚拟机是否使用根据-XX:+/-UseTLAB参数设置。
虽然Java堆是线程共享的,但也有可能一些内存实际上是线程独享的。
| 初始化
现在对象的位置知道了,空间也分配了。但是里面还是空荡荡的一块。现在就要创造出内容来。
根据上图分三步:
1、 设置属性的零值
因为在TLAB模式下,初始化属性的零值已经设置过了,所以这里有可能不需要设置。只有设置了值,我们才能在调用的时候才能获取到正确的值。举例如下图:
打印出来分别是0、null、false。我们之所以能打印出来这些,就是因为这里的初始化。如果没有这一步有可能data1打印出来的就不是0。data2打印出来的就更加不知道是什么了。
2、 设置头信息
对象里面要存必要的东西,比如对象类型信息。如果是Java数组还要记录数组的长度。以及一些其他信息如下图:
3、 根据我们自己的意向再次进行配置
这一步就是我们平时的初始化了,比如new的时候调用的构造函数,去初始化设置一些值。
| 找到她
创建好了,那么我们平时是怎么找到的呢?
结合我上一篇文章,Java虚拟机栈来讲更加有连贯性。如下图:
访问方式一共分两种:
1、 通过句柄方式访问。在Java堆中维护一个句柄池。每个句柄包含一个对象实例数据指针和一个对象类型数据指针。然后在Java虚拟机栈的栈帧里面的变量表对对象的引用指向的是句柄。这样做的好处是在Java堆中进行了垃圾回收,对象的地址发生了改变的时候,只需要修改句柄的对象实例数据指针就行。
2、 直接引用:栈中的引用的是对象的实际地址。这样做的好处是访问更快。
| 总结
可以看到JVM创建一个对象经历了不少的流程。不过总结起来和我们平时做很多事情是一样。每个流程都合情合理,不多不少。
每一个步骤都有可能有问题,但同时也解决了这些问题。比如类信息为什么是放到方法区。分配内存对象是并发问题的处理。
流程的梳理和每个地方出现问题的解决方式都值得我们平时开发的时候的学习。
Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!