创建对象的过程,相信很多人都不陌生,这个操作无关你是新手还是老手,学过java的,基本都是懂得简简单单的使用new,创建一个类的对象
我以前也觉得,一个小小的new,不是每个人都会吗?在我深入学习了JVM之后,我发现,我以前的小小的一个new,在JVM里就是一个很复杂的过程
例如,我要创建一个学生对象,我或许会很简单的写到
Student student = new Student();
在这个过程中,JVM到底发生了什么复杂而有趣的事情呢?我来告诉你
首先,JVM会现在常量池搜索这个类是否已经存在其符号引用,检查Student类是否被加载,解析和初始化过,如果没有,则先开始类加载
随后,JVM会帮此对象分配内存,这个时候,要分为两种情况讨论
1.若堆内存绝对规整,即可用的内存空间和不可用的内存空间分成两块,中间只是用指针来作为分界线,这种情况下,指针向可用内存这边移动相应大小的内存进行分配,此过程称为指针碰撞(Bump the Pointer)以下称为BTP
2.若堆内存并非绝对规整,即可用和不可用的内存零零碎碎地存在,形成一些内存块,此时,需要一张表来维护,称为空闲列表(Free List),用以记录每个内存块是否可用,可用空间有多大,在此表中寻找可用的,且内存足够分配的内存块划分内存
对内存是否规整,取决于使用的GC是否用到压缩整理算法,若是Serial,ParNew等带有Compact过程的则使用BTP分配空间,像CMS这些基于Mark-Sweep的则使用空闲列表
在分配内存的时候,存在并发问题,并非线程安全
解决方案:
1.分配内存动作采取同步,用CAS配上失败重试来保证操作的原子性
2.用本地线程缓冲(Thread Local Allocation Buffer)以下简称TLAB,线程在自己的TLAB上分配内存,当TLAB用完需分配内存时,采用同步的形式分配TLAB空间
JVM是否启用TLAB需要用参数-XX:+/-UseTLAB决定
内存分配完后,JVM令已分配的内存空间初始化为零值,此操作使得对象不赋予初始值也能使用
接下来,JVM往对象头里面存入各种信息(属于哪个类的实例,哈希值,元数据信息,GC分代年龄等信息)
至此,对于JVM而言,对象已被创建,之后就按照程序员的意愿进行初始化,调用<init>方法