从汇编码分析java对象的创建过程(推荐)

源码:

class T {
	int m = 8;
}
T t = new T();

汇编码:

0 new #2 
3 dup
4 invokespecial #3 >
7 astore_1
8 return

new #2

申请内存,在堆里面创建一个新对象。

半初始化,新建对象中的m值是0。

dup

复制操作,因为invokespecial会消耗一份引用,所以先复制一份

invokespecial

4 invokespecial #3

init是调用它的构造方法。

此时对象中的m值是8。

astore_1

将符号和对象建立关联,即t和堆中的对象。

其实很简单,今天看一个视频说了半天。。。

知识点补充:java对象的创建过程

大家都知道,java使用new 关键字进行对象的创建,但这只是从语言层次上理解了对象的创建,下边我们从jvm的角度来看看,对象是怎么被创建出来的,即对象的创建过程。

对象的创建大概分为以下几步:

1:检查类是否已经被加载;

2:为对象分配内存空间;

3:为对象字段设置零值;

4:设置对象头;

5:执行构造方法。

第一步,当程序遇到new 关键字时,首先会去运行时常量池中查找该引用所指向的类有没有被虚拟机加载,如果没有被加载,那么会进行类的加载过程,如果已经被加载,那么进行下一步,为对象分配内存空间;

第二步,加载完类之后,需要在堆内存中为该对象分配一定的空间,该空间的大小在类加载完成时就已经确定下来了,这里多说一点,为对象分配内存空间有两种方式:

(1)第一种是jvm将堆区抽象为两块区域,一块是已经被其他对象占用的区域,另一块是空白区域,中间通过一个指针进行标注,这时只需要将指针向空白区域移动相应大小空间,就完成了内存的分配,当然这种划分的方式要求虚拟机的对内存是地址连续的,且虚拟机带有内存压缩机制,可以在内存分配完成时压缩内存,形成连续地址空间,这种分配内存方式成为“指针碰撞”,但是很明显,这种方式也存在一个比较严重的问题,那就是多线程创建对象时,会导致指针划分不一致的问题,例如A线程刚刚将指针移动到新位置,但是B线程之前读取到的是指针之前的位置,这样划分内存时就出现不一致的问题,解决这种问题,虚拟机采用了循环CAS操作来保证内存的正确划分;

(2)第二种也是为了解决第一种分配方式的不足而创建的方式,多线程分配内存时,虚拟机为每个线程分配了不同的空间,这样每个线程在分配内存时只是在自己的空间中操作,从而避免了上述问题,不需要同步。当然,当线程自己的空间用完了才需要需申请空间,这时候需要进行同步锁定。为每个线程分配的空间称为“本地线程分配缓冲(TLAB)”,是否启用TLAB需要通过 -XX:+/-UseTLAB参数来设定。

第三步,分配完内存后,需要对对象的字段进行零值初始化,对象头除外,零值初始化意思就是对对象的字段赋0值,或者null值,这也就解释了为什么这些字段在不需要进程初始化时候就能直接使用;

第四步,这里,虚拟机需要对这个将要创建出来的对象,进行信息标记,包括是否为新生代/老年代,对象的哈希码,元数据信息,这些标记存放在对象头信息中,对象头非常复杂,这里不作解释,可以另行百度;

第五步,也就是最后一步,执行对象的构造方法,这里做的操作才是程序员真正想做的操作,例如初始化其他对象啊等等操作,至此,对象创建成功。

这里其实讲的比较粗浅,只是对象创建的大概过程,例如对象头、类的加载等等都是非常复杂的过程,我会在接下来解释。

总结

到此这篇关于从汇编码分析java对象的创建过程的文章就介绍到这了,更多相关从汇编码分析java对象的创建过程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(从汇编码分析java对象的创建过程(推荐))