暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

深入理解JVM搬运工(1) Java内存区域之对象创建过程

nullPoint水 2018-06-10
186

声明:本文基于《深入理解Java虚拟机》一书,可以看作是该书的读书笔记


定位符号引用

    虚拟机遇到new指令时,首先检查该指令的参数是否可以在常量池中定位到类符号引用,并检查符号引用代表的类是否已经被加载、解析和初始化过。如果没有,则进行类加载。

分配内存

    经过类加载检查并且通过后,下一步虚拟机为新生对象分配内存。

    对象所需内存大小在类加载后便可确定,给对象分配内存相当于从java堆中划分出一块确定大小的内存。当虚拟机使用的是Serial、ParNew等带有Compact过程的收集器时,由于java堆中内存绝对规整(所有用过的内存在一边,空闲的内存在另一边。),虚拟机采用的是“指针碰撞”的方式进行分配;当虚拟机使用的是CMS这种基于Mark-Sweep算法的收集器时,由于java堆中内存并不是规整的。采用的是“空闲列表”的方式进行分配

    指针碰撞:java堆内存绝对规整,用过的内存和空闲内存边界明确,那么分配内存时仅需将指针从边界向空闲内存移动一段与对象大小相等的距离,该内存分配方式成为指针碰撞

    空闲列表:java对内存并不规整,已使用的内存和空闲的内存相互交错,那么分配内存就不是简单的指针碰撞了,虚拟机需要单独维护一个列表,该列表积累了哪些内存块是可以用的,在分配时从列表中找到一块足够大的空间划分给对象,并更新列表上的记录,这种分配方式被称为空闲列表。

    在划分内存空间时,由于对象创建是一个非常频繁的行为,所以需要考虑在并发的环境下如何保证成功划分内存空间。解决方案也有两种:一种方式是在分配内存空间时进行同步处理,虚拟机采用CAS+失败重试的方式保证分配内存的原子性。另一种方式是将内存分配按照线程划分在不同的空间中进行,即每个线程在java对中预先分配一小块被称为“本地线程分配缓冲(Thread Local Allocation Buffer ,TLAB)”的内存,哪个线程需要分配内存,就在哪个线程的TLAB上分配,只用TLAB用完并分配新的TLAB是,才需要同步锁定。虚拟机是否使用TLAB通过-XX:+/-UseTLAB参数设定。

准备

    内存分配完毕后进入准备阶段:虚拟机将分配到的内存空间都初始化为0值(不包括对象头),如果使用的是TLAB,这一过程可以提前至TLAB分配是进行。

对象头设置

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

初始化

    完成对象头的设置对于虚拟机来说,一个新的对象已经产生,但是对于java程序来说,对象只是内创建了还未进行初始化,所有的值都为0。接下来需要执行<init>方法,把对象按照程序员的意愿进行初始化。




文章转载自nullPoint水,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论