HotSpot虚拟机——对象内存创建(文中讨论的限于普通对象,不包括数组和Class对象等)

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

   (2).在类加载完成后,虚拟机为新生对象分配内存,对象所需的内存大小在类加载完后便完成确定。为对象分配内存的任务等同于把一个固定大小的内存在Java堆中划分出来,在单线程的情况下,一般有两种分配策略:
        2.1、指针碰撞
            这种一般适用于内存是规整的(内存是否规整取决于内存回收策略),分配空间的工作只是将指针像空闲内存一侧移动    对象大小的距离即可。
        2.2、空闲列表
            这种适用于内存非规整的情况,这种情况下JVM会维护一个内存列表,记录那些内存区域是空闲的,大小是多少哦啊。给对象分配空间的时候去空闲列表里查询到合适的区域然后进行分配即可
       但是JVM不可能一直在单线程状态下运行,那样效率太差了。由于再给一个对象分配内存的时候不是原子性的操作,至少需要以下几步:查找空闲列表、分配内存、修改空闲列表等等,这是不安全的。解决并发时的安全问题也有两种策略:
        2.3、CAS
            实际上虚拟机采用CAS配合上失败重试的方式保证更新操作的原子性,原理和上面讲的一样。
        2.4、TLAB
            如果使用CAS其实对性能还是会有影响的,所以JVM又提出了一种更高级的优化策略:每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲区(TLAB),线程内部需要分配内存时直接在TLAB上分配就行,避免了线程冲突。只有当缓冲区的内存用光需要重新分配内存的时候才会进行CAS操作分配更大的内存空间。 虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来进行配置(jdk5及以后的版本默认是启用TLAB的。

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

    (4).虚拟机要对对象进行必要的设置,例如:这个对象是那个实例,如何找到类的元素信息、对象打哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头之中。根据虚拟机当前的运行状态不同,如是否启用偏向锁等,对象头有不同的设置方式。

   (5)执行New 指令之后接着是执行<init>方法,把对象按照程序员的意愿进行初始化,这样一个真正的对象才算完全生产出来。

猜你喜欢

转载自blog.csdn.net/u013836676/article/details/79863783