对象的创建

来源:互联网 发布:java 编程思想笔试题 编辑:程序博客网 时间:2024/05/20 04:31


创建对象语句Clazz instance = new Clazz();包含的主要过程包括了类加载检查、对象分配内存、并发处理、内存空间初始化、对象设置、执行init方法等。 

主要流程如下: 


1. 类加载检查

JVM遇到一条new指令时,首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类的加载过程。

2. 对象分配内存

对象所需内存的大小在类加载完成后便完全确定(对象内存布局),为对象分配空间的任务等同于把一块确定大小的内存Java中划分出来。

根据内存是否规整(由所采用的gc是否带有压缩整理功能决定)有两种方式:

· (1)指针碰撞(Bump the pointer) 
Java堆中的内存是规整的,所有用过的内存都放一边,空闲的放另一边,中间放一个指针作为分界点的指示器,分配内存就把指针向空闲那边移动一段。例如:Serial、ParNew等收集器。

· (2)空闲列表(Free List) 
已使用的和空闲的内存相互交错,虚拟机必须维护一张列表,记录哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录。例如:CMS这种基于Mark-Sweep算法的收集器。

3. 并发处理

可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的情况,所以要保证一致性:

1同步 
虚拟机采用CAS配上失败重试的方式保证更新操作的原子性

2本地线程分配缓冲(Thread Local Allocation Buffer, TLAB) 
把内存分配的动作按照线程划分为在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存(TLAB)。哪个线程要分配内存,就在哪个线程的TLAB上分配。只有TLAB用完并分配新的TLAB时,才需要同步锁定。

4. 内存空间初始化

虚拟机将分配到的内存空间都初始化为零值(不包括对象头),如果使用了TLAB,这一工作过程也可以提前至TLAB分配时进行。内存空间初始化保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。

注意:类的成员变量可以不显示地初始化(Java虚拟机都会先自动给它初始化为默认值)。方法中的局部变量如果只负责接收一个表达式的值,可以不初始化,但是参与运算和直接输出等其它情况的局部变量需要初始化。

5. 对象设置

虚拟机对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头之中。

6. 执行init()

在上面的工作都完成之后,从虚拟机的角度看,一个新的对象已经产生了。但是从Java程序的角度看,对象的创建才刚刚开始init()方法还没有执行,所有的字段都还是零。

所以,一般来说(由字节码中是否跟随invokespecial指令所决定),执行new指令之后会接着执行init()方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算产生出来。

invokespecial指令

invokespecial和invokevirtual

7.注意:在系统调用构造器之前已经创建了一个对象,只是这个对象还不能被外界访问,构造器调用对象的this引用,在构造器执行结束后这个对象作为返回值被返回。

原创粉丝点击