标签:
这一节我们来讨论一下JVM对象建立过程。
对象的建立过程
图一:对象建立过程
1、类加载检查。
当JVM检测到有一条new指令时,首先先检查该指令的参数是否在常量池中定位到一个类的符号引用,并检查这个符号引用所代表的类是否已被加载、解析和初始化过。如果存在的话,JVM将直接使用已有的信息对该类进行操作。
如果没有,则执行相应的类加载过程。
2、为新生对象分配内容。
不同的JVM垃圾收集器在内容分配的时候的表现也不相同。
如果使用的收集器带有压缩整理过程,则进行指针碰撞,因为收集器带有压缩整理,所以整个堆内存是绝对规整的,分配内存就仅仅是把指针向空闲空间那边挪动一段与对象大小相等的距离作为对象的内存。
如果使用的收集器不带有压缩整理过程,此时JVM维护着一个空闲列表,记录着可用的内存块位置和大小,分配时在列表中找到足够大的空间划分给对象实例。
内存分配完成后,分配到的内存空间都初始化为零,但不包括对象头。
值得注意的是
内存分配时的同步问题可以通过以下两种方式进行同步:
a、对分配内存空间的动作进行同步处理。虚拟机采用CAS(比较并交配,通过3个操作数,内存值V,旧的预期值A、要修改的新值B,当且仅当预期值A和内存值V相同时,才将内存值改成B,否则不分配内存)配上失败重试方式来保证更新操作的原子性。
b、把内存的分配动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中先预留一块本地线程分配缓冲(TLAB)。哪个线程分配内存时,就在哪个线程的TLAB分配,只有当TLAB用完并分配新的TLAB时,才需要同步锁定。
3、对对象进行必要的设置。
例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头之中。
4、初始化对象。
当完成上述操作后,对象的内存便分配成功了,但是所有的字段都还是零。
此时应该执行方法,把对象按照程序员的意愿进行初始化,从而产生一个真正可用的对象。
对象的内存布局分为三个区域:
a、对象头,b、实例数据,c、对齐填充。
对象的访问方式由虚拟机实现,主流的访问方式有两种:
1、使用句柄访问,Java堆中将会划分出一块内存来作为句柄池,reference中存储的是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。
2、直接指针访问。Java堆需要考虑如何放置访问类型数据的相关信息,此时reference存放的是对象地址。
两种访问方式的对比:
目前使用直接指针访问的方式比较常用。因为对象的访问在Java程序运行过程中是比较频繁的,积少成多也会造成太多的时间开销。
标签:
原文地址:http://www.cnblogs.com/zhouyuqin/p/5161680.html