JVM学习之二 java对象的创建

对象的创建

    谈及Java,就离不开对象,因为java是面向对象的编程语言。至于什么是对象的概念,虽然已经接触java两年有余仍不能一言以蔽之,网上相关的博客甚多,大家可以前往参考。今天就具象的学习下怎么创建对象,也就是对象的创建过程。java的对象主要分为三类:普通的java对象,数组,Class对象,后两者与区别于我们普通的java对象,本文也主要学习的是第一种对象的创建,后两种后面的文章会学习。

一 类的加载

    虚拟机遇到一个new指令时,首先检查这个指令的参数能否在产量池中定位到一个类的符号引用,并且检查这个符号引用是否已经被加载 解析和初始化过,如果没有则执行相应的类加载。

二 分配内存

    类加载检查通过后,虚拟就需要为对象分配内存。内存的大小在类加载完成后便可确定。内存的分配方式根据堆所采用的垃圾收集器是否带有压缩整理功能又分为指针碰撞和空闲列表。

    指针碰撞方式:因为该方式的java堆收集器带有整理压缩功能,比如Serial、ParNew等,这堆内存是规整的,用过的内存放在一边,空闲的内存放在一边,中间放着一个指针作为分界点的指示器,分配内存就是将指示器向空闲内存挪动一段与对象大小相等的距离。

    空闲列表方式:如果jvm采用的gc没有整理压缩功能,则堆内存中已使用和未使用的内存是不规整的,这个时候我们分配内存不能是简单的挪动一个分界点指示器就行。jvm会维护一个列表,用来记录未使用的内存。当需要给对象分配内存的时候,会在表中找到一个合适大小的内存记录,然后将此内存记录代表的内存分配给该对象,同时将未用内存的列表进行更新,此方式即为空闲列表方式。

    内存分配的过程,有时候需要考虑并发的情况。有两种方案可供参考:

    内存分配作同步处理,jvm采用的是CAS配上失败重试的方式保证更新操作的原子性;线程空间隔离,每个线程预先在堆中分配一小块内存,叫做本地线程分配缓存(thread local allocation buffer)。那个线程要分配内存就在该线程的tlab中分配,如果用完了就分配新的,但是在分配新的tlab时需要做同步锁定。通过-XX:+/-UseTLAB设定该参数来决定是否使用TLAB。

三 初始化零值

    分配内存之后,虚拟机要对内存空间进行初始化零值(不包括对象头)。此初始化零值指数据类型的默认值,比如boolean类型的默认值为false等。如果内存分配时使用了TLAB,则该过程可以提前至TLAB分配内存时。这也就是为什么我们能使用类实例变量但是没有赋初始值给它们。

四 必要设置

    对对象头中的信息进行必要的设置,比如该对象是哪个类的实例,如何才能找到该类的元数据信息等。此阶段执行完毕,就代表虚拟机创建对象完成了,但是从java的角度讲下面才是真正的创建开始。

五 自定义初始化

    new指令执行完毕之后会执行<init>方法,也就是按照程序员的意愿对对象进行初始化,会将第三步中的初始化零值替换为程序员指定的构造函数中的实例变量的值,这也就是构造函数的实际意义所在。

    声明:本博客中大量参考引用了周志明作者《深入理解java虚拟机》2版中的第二章节的内容,也可以看作是本书的学习笔记。

猜你喜欢

转载自blog.csdn.net/tony_java_2017/article/details/80588352